React의 양식: React 갈고리 양식 및 재료 UI 및 YUP
react의 이런 폼 라이브러리는 React Hook Form
왜 React-Hook 양식을 사용합니까?
나는 몇 개의 폼 라이브러리를 시험해 보았는데, 그 중에서 가장 유행하는 것은 Formik이지만, React-Hook-form처럼 그렇게 빠른 것은 하나도 없다.내 웹 응용 프로그램에서 내 폼은 보통 60-70개의 필드가 있는데, 이렇게 많은 필드에 대해 폼 라이브러리가 성능 면에서 폼과 필적할 수 있는 것은 하나도 없다. 설령 Formik일지라도.
목표
본고에서 우리는 텍스트 필드, Select of Material UI, MultiSelect of react Select와react Hook form 등 다시 사용할 수 있는 폼 구성 요소를 만드는 방법을 소개할 것이다.Yup을 사용하여 양식 검증을 하고 React-Hook 양식과 어떻게 통합하는지 살펴보겠습니다.
본고의 마지막 부분에서 나는githubrepo를 공유할 것이다. 그 중에서 나는 Material UI의 모든 폼 구성 요소와 React-Hook 폼을 포함하고 사람들이 쉽게 그것을 인용하거나 그들의 프로젝트에 집적할 수 있다
카탈로그
이 문장은 매우 길다.그래서 나는 문장을 몇 부분으로 나누었다
본고에서 우리는 텍스트 필드, Select of Material UI, MultiSelect of react Select와react Hook form 등 다시 사용할 수 있는 폼 구성 요소를 만드는 방법을 소개할 것이다.Yup을 사용하여 양식 검증을 하고 React-Hook 양식과 어떻게 통합하는지 살펴보겠습니다.
본고의 마지막 부분에서 나는githubrepo를 공유할 것이다. 그 중에서 나는 Material UI의 모든 폼 구성 요소와 React-Hook 폼을 포함하고 사람들이 쉽게 그것을 인용하거나 그들의 프로젝트에 집적할 수 있다
카탈로그
이 문장은 매우 길다.그래서 나는 문장을 몇 부분으로 나누었다
Basic form element binding with React Hook Form
초기 설정
We will use create-react-app
for this article. Follow the below steps to setup the basics
npx create-react-app hook-form-mui
cd hook-form-mui
npm install @material-ui/core @material-ui/icons react-hook-form yup @hookform/resolvers react-select styled-components @material-ui/pickers @date-io/[email protected] moment
Once all the packages are installed, run the app once.
npm start
You will see the below page
기본 양식 요소와 React-Hook 양식 바인딩
1. 텍스트 필드
Create a folder in the src named controls. Inside controls folder create a folder input. Inside input folder create a file index.js (src -> controls -> input -> index.js)
index.js will have below code
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import TextField from "@material-ui/core/TextField";
function FormInput(props) {
const { control } = useFormContext();
const { name, label } = props;
return (
<Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
{...props}
/>
);
}
export default FormInput;
Lets deep dive into the above code.
When using React Hook Form, two primary concepts need to be kept in mind,
- We have to register each form field that we use. This helps in form submission and validation.
- Each form field should have a unique name associated with it.
In the above code, we are using a wrapper component called Controller
provided by react-hook-form
to register our form fields (in this case) TextField
component.
As you can see we can pass additional props of TextField
component and other props directly to the Controller
component
<Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
InputLabelProps={{
className: required ? "required-label" : "",
required: required || false,
}}
error={isError}
helperText={errorMessage}
{...props}
/>
control
object contains methods for registering a controlled component into React Hook Form. The control
object needs to be pass as a prop to the Controller
component.
control
object is declared as :
const { control } = useFormContext();
In App.js
, we will have the following code:
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
function App(props) {
const methods = useForm();
const { handleSubmit } = methods;
const onSubmit = (data) => {
console.log(data);
};
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}> // pass all methods into the context
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
Let's deep dive into the App.js
code.
The most important function is useForm()
which is a hook provided by react-hook-form
. useForm()
contains various methods which is required for form validation, submission and registration of the form fields.
const methods = useForm();
const { handleSubmit } = methods;
As in the above code useForm()
provides a method
object which contains handleSubmit
function which is used for form submission on button click. In this case SUBMIT
button.
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
</Grid>
</form>
</FormProvider>
In the above block of code, we declare a FormProvider
component under which our form and its respective fields will be declared. Also, we need to pass all the functions and objects of methods
to FormProvider
component. This is required as we are using a deep nested structured of custom form fields and the useFormContext()
used in the FormInput
component need to consume the functions and objects of methods
For the FormInput
component we just need to pass name
and label
props.
<FormInput name="name" label="Name" />
If you run the app, you should see:
이름 필드에 텍스트를 입력하고 제출 버튼을 클릭합니다.dev 컨트롤러에서 출력을 검사합니다.출력은 필드 이름과 상응하는 값을 가진 대상이 됩니다.
현재, 우리는 계속해서 유사한 방식으로 다른 필드 구성 요소를 만들 것이다.
2. 선택
Create a new folder name styles under src. Create a new file index.js under styles folder (src -> styles -> index.js)
index.js will have following code
import styled from "styled-components";
import { InputLabel } from "@material-ui/core";
export const StyledInputLabel = styled(InputLabel)`
&& {
.req-label {
color: #f44336;
}
}
`;
I'm using styled-components
for my styling. StyledInputLabel
will be used below in the FormSelect
component. The main purpose of the above styling will be used during validation.
Create a new folder name select under controls, inside select folder create a index.js file (controls -> select -> index.js).
index.js will have following code
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import InputLabel from "@material-ui/core/InputLabel";
const MuiSelect = (props) => {
const { label, name, options } = props;
return (
<FormControl fullWidth={true}>
<InputLabel htmlFor={name}>{label}</InputLabel>
<Select id={name} {...props}>
<MenuItem value="">
<em>None</em>
</MenuItem>
{options.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</FormControl>
);
};
function FormSelect(props) {
const { control } = useFormContext();
const { name, label } = props;
return (
<React.Fragment>
<Controller
as={MuiSelect}
control={control}
name={name}
label={label}
defaultValue=""
{...props}
/>
</React.Fragment>
);
}
export default FormSelect;
Things to note in the above code
-
MuiSelect
function is a component which contains our UI for the rendering of the Select field. There are three main props name
, label
and options
. options
is an array of objects that contains the data to be displayed in the dropdown.
-
FormSelect
is similar to FormInput
component where again we are using useFormContext()
method, Controller
component and control
object.
Let's see how we consume FormSelect
in the App.js. Below is the new code in App.js
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
import FormSelect from "./controls/select";
function App(props) {
const methods = useForm();
const { handleSubmit } = methods;
const onSubmit = (data) => {
console.log(data);
};
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={numberData} />
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
What has changed in the App.js
- I have created data (array of objects) that we will pass to the
FormSelect
.
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
- I have added following code to the render
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={noData} />
</Grid>
Now your web page will look like:
양식 데이터를 작성한 다음 제출 단추를 누르십시오.dev 컨트롤러의 출력을 검사합니다.
3. 자동 완성 기능이 있는 다중 선택(반응 선택)
Here we will be using one of the most popular react libraries React-Select . 새 폴더 이름을 만듭니다. "컨트롤"에서 "자동완성"을 선택하고, "자동완성 폴더 선택""두 파일 만들기"인덱스에서 선택하십시오.js와 색인.css 파일
인덱스로 이동합니다.js는 styles 폴더에 다음 코드를 추가합니다.
export const StyledFormControl = styled(FormControl)`
&& {
width: 100%;
display: block;
position: relative;
}
`;
export const StyledAutoSelectInputLabel = styled(InputLabel)`
&& {
position: relative;
.req-label {
color: #f44336;
}
transform: translate(0, 1.5px) scale(0.75);
transform-origin: top left;
}
`;
인덱스로 이동합니다.css는 "자동 완성 폴더 선택"아래에 다음 코드를 추가합니다.
.autoselect-options {
padding: 6px 16px;
line-height: 1.5;
width: auto;
min-height: auto;
font-size: 1rem;
letter-spacing: 0.00938em;
font-weight: 400;
cursor: pointer;
}
.autoselect-options:hover {
background-color: rgba(0, 0, 0, 0.14) !important;
}
저는 스타일 변경에 두 가지 목적이 있습니다. 첫 번째 목적은 오류 처리에 인증을 추가할 때 사용하고, 두 번째 목적은 React Select를 Material UI Select에 가깝게 보이는 것입니다.
인덱스로 이동합니다.js는 자동 완성 폴더 선택에 다음 코드를 추가합니다.
import React, { useEffect, useState } from "react";
import { useFormContext, Controller } from "react-hook-form";
import Select, { createFilter } from "react-select";
import { StyledFormControl, StyledAutoSelectInputLabel } from "../../styles";
import "./index.css";
const stylesReactSelect = {
clearIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
indicatorSeparator: (provided, state) => ({
...provided,
margin: 0,
}),
dropdownIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
placeholder: (provided, state) => ({
...provided,
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
color: state.selectProps.error ? "#f44336" : "rgba(0, 0, 0, 0.54)",
}),
control: (provided, state) => ({
...provided,
borderRadius: 0,
border: 0,
borderBottom: state.selectProps.error
? "1px solid #f44336"
: "1px solid rgba(0,0,0,0.87)",
boxShadow: "none",
":hover": {
borderColor: state.selectProps.error ? "1px solid #f44336" : "inherit",
boxShadow: state.selectProps.error ? "1px solid #f44336" : "none",
},
}),
valueContainer: (provided, state) => ({
...provided,
paddingLeft: 0,
}),
};
const components = {
Option,
};
function Option(props) {
const { onMouseMove, onMouseOver, ...newInnerProps } = props.innerProps;
return (
<div {...newInnerProps} className="autoselect-options">
{props.children}
</div>
);
}
const ReactSelect = (props) => {
const { label, options, name } = props;
return (
<React.Fragment>
<StyledFormControl>
<StyledAutoSelectInputLabel>
<span>{label}</span>
</StyledAutoSelectInputLabel>
<Select
options={options}
placeholder="Please Select"
valueKey="id"
components={components}
isClearable={true}
styles={stylesReactSelect}
isSearchable={true}
filterOption={createFilter({ ignoreAccents: false })}
{...props}
/>
</StyledFormControl>
</React.Fragment>
);
};
function FormSelectAutoComplete(props) {
const { control } = useFormContext();
const { name, label, options } = props;
const [newData, setNewData] = useState([]);
useEffect(() => {
const newOptions = options.map((data, index) => ({
label: data.label,
value: data.id,
}));
setNewData(newOptions);
}, [options]);
return (
<React.Fragment>
<Controller
as={ReactSelect}
name={name}
control={control}
label={label}
{...props}
options={newData}
/>
</React.Fragment>
);
}
export default FormSelectAutoComplete;
코드를 분해합시다.
const stylesReactSelect = {
clearIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
indicatorSeparator: (provided, state) => ({
...provided,
margin: 0,
}),
dropdownIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
placeholder: (provided, state) => ({
...provided,
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
color: state.selectProps.error ? "#f44336" : "rgba(0, 0, 0, 0.54)",
}),
control: (provided, state) => ({
...provided,
borderRadius: 0,
border: 0,
borderBottom: state.selectProps.error
? "1px solid #f44336"
: "1px solid rgba(0,0,0,0.87)",
boxShadow: "none",
":hover": {
borderColor: state.selectProps.error ? "1px solid #f44336" : "inherit",
boxShadow: state.selectProps.error ? "1px solid #f44336" : "none",
},
}),
valueContainer: (provided, state) => ({
...provided,
paddingLeft: 0,
}),
};
create-react-app
for this article. Follow the below steps to setup the basicsnpx create-react-app hook-form-mui
cd hook-form-mui
npm install @material-ui/core @material-ui/icons react-hook-form yup @hookform/resolvers react-select styled-components @material-ui/pickers @date-io/[email protected] moment
npm start
1. 텍스트 필드
Create a folder in the src named controls. Inside controls folder create a folder input. Inside input folder create a file index.js (src -> controls -> input -> index.js)
index.js will have below code
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import TextField from "@material-ui/core/TextField";
function FormInput(props) {
const { control } = useFormContext();
const { name, label } = props;
return (
<Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
{...props}
/>
);
}
export default FormInput;
Lets deep dive into the above code.
When using React Hook Form, two primary concepts need to be kept in mind,
- We have to register each form field that we use. This helps in form submission and validation.
- Each form field should have a unique name associated with it.
In the above code, we are using a wrapper component called Controller
provided by react-hook-form
to register our form fields (in this case) TextField
component.
As you can see we can pass additional props of TextField
component and other props directly to the Controller
component
<Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
InputLabelProps={{
className: required ? "required-label" : "",
required: required || false,
}}
error={isError}
helperText={errorMessage}
{...props}
/>
control
object contains methods for registering a controlled component into React Hook Form. The control
object needs to be pass as a prop to the Controller
component.
control
object is declared as :
const { control } = useFormContext();
In App.js
, we will have the following code:
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
function App(props) {
const methods = useForm();
const { handleSubmit } = methods;
const onSubmit = (data) => {
console.log(data);
};
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}> // pass all methods into the context
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
Let's deep dive into the App.js
code.
The most important function is useForm()
which is a hook provided by react-hook-form
. useForm()
contains various methods which is required for form validation, submission and registration of the form fields.
const methods = useForm();
const { handleSubmit } = methods;
As in the above code useForm()
provides a method
object which contains handleSubmit
function which is used for form submission on button click. In this case SUBMIT
button.
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
</Grid>
</form>
</FormProvider>
In the above block of code, we declare a FormProvider
component under which our form and its respective fields will be declared. Also, we need to pass all the functions and objects of methods
to FormProvider
component. This is required as we are using a deep nested structured of custom form fields and the useFormContext()
used in the FormInput
component need to consume the functions and objects of methods
For the FormInput
component we just need to pass name
and label
props.
<FormInput name="name" label="Name" />
이름 필드에 텍스트를 입력하고 제출 버튼을 클릭합니다.dev 컨트롤러에서 출력을 검사합니다.출력은 필드 이름과 상응하는 값을 가진 대상이 됩니다.
현재, 우리는 계속해서 유사한 방식으로 다른 필드 구성 요소를 만들 것이다.
2. 선택
Create a new folder name styles under src. Create a new file index.js under styles folder (src -> styles -> index.js)
index.js will have following code
import styled from "styled-components";
import { InputLabel } from "@material-ui/core";
export const StyledInputLabel = styled(InputLabel)`
&& {
.req-label {
color: #f44336;
}
}
`;
I'm using styled-components
for my styling. StyledInputLabel
will be used below in the FormSelect
component. The main purpose of the above styling will be used during validation.
Create a new folder name select under controls, inside select folder create a index.js file (controls -> select -> index.js).
index.js will have following code
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import InputLabel from "@material-ui/core/InputLabel";
const MuiSelect = (props) => {
const { label, name, options } = props;
return (
<FormControl fullWidth={true}>
<InputLabel htmlFor={name}>{label}</InputLabel>
<Select id={name} {...props}>
<MenuItem value="">
<em>None</em>
</MenuItem>
{options.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</FormControl>
);
};
function FormSelect(props) {
const { control } = useFormContext();
const { name, label } = props;
return (
<React.Fragment>
<Controller
as={MuiSelect}
control={control}
name={name}
label={label}
defaultValue=""
{...props}
/>
</React.Fragment>
);
}
export default FormSelect;
Things to note in the above code
-
MuiSelect
function is a component which contains our UI for the rendering of the Select field. There are three main propsname
,label
andoptions
.options
is an array of objects that contains the data to be displayed in the dropdown. -
FormSelect
is similar toFormInput
component where again we are usinguseFormContext()
method,Controller
component andcontrol
object.
Let's see how we consume FormSelect
in the App.js. Below is the new code in App.js
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
import FormSelect from "./controls/select";
function App(props) {
const methods = useForm();
const { handleSubmit } = methods;
const onSubmit = (data) => {
console.log(data);
};
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={numberData} />
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
What has changed in the App.js
- I have created data (array of objects) that we will pass to the
FormSelect
.
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
- I have added following code to the render
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={noData} />
</Grid>
양식 데이터를 작성한 다음 제출 단추를 누르십시오.dev 컨트롤러의 출력을 검사합니다.
3. 자동 완성 기능이 있는 다중 선택(반응 선택)
Here we will be using one of the most popular react libraries React-Select . 새 폴더 이름을 만듭니다. "컨트롤"에서 "자동완성"을 선택하고, "자동완성 폴더 선택""두 파일 만들기"인덱스에서 선택하십시오.js와 색인.css 파일인덱스로 이동합니다.js는 styles 폴더에 다음 코드를 추가합니다.
export const StyledFormControl = styled(FormControl)`
&& {
width: 100%;
display: block;
position: relative;
}
`;
export const StyledAutoSelectInputLabel = styled(InputLabel)`
&& {
position: relative;
.req-label {
color: #f44336;
}
transform: translate(0, 1.5px) scale(0.75);
transform-origin: top left;
}
`;
인덱스로 이동합니다.css는 "자동 완성 폴더 선택"아래에 다음 코드를 추가합니다..autoselect-options {
padding: 6px 16px;
line-height: 1.5;
width: auto;
min-height: auto;
font-size: 1rem;
letter-spacing: 0.00938em;
font-weight: 400;
cursor: pointer;
}
.autoselect-options:hover {
background-color: rgba(0, 0, 0, 0.14) !important;
}
저는 스타일 변경에 두 가지 목적이 있습니다. 첫 번째 목적은 오류 처리에 인증을 추가할 때 사용하고, 두 번째 목적은 React Select를 Material UI Select에 가깝게 보이는 것입니다.인덱스로 이동합니다.js는 자동 완성 폴더 선택에 다음 코드를 추가합니다.
import React, { useEffect, useState } from "react";
import { useFormContext, Controller } from "react-hook-form";
import Select, { createFilter } from "react-select";
import { StyledFormControl, StyledAutoSelectInputLabel } from "../../styles";
import "./index.css";
const stylesReactSelect = {
clearIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
indicatorSeparator: (provided, state) => ({
...provided,
margin: 0,
}),
dropdownIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
placeholder: (provided, state) => ({
...provided,
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
color: state.selectProps.error ? "#f44336" : "rgba(0, 0, 0, 0.54)",
}),
control: (provided, state) => ({
...provided,
borderRadius: 0,
border: 0,
borderBottom: state.selectProps.error
? "1px solid #f44336"
: "1px solid rgba(0,0,0,0.87)",
boxShadow: "none",
":hover": {
borderColor: state.selectProps.error ? "1px solid #f44336" : "inherit",
boxShadow: state.selectProps.error ? "1px solid #f44336" : "none",
},
}),
valueContainer: (provided, state) => ({
...provided,
paddingLeft: 0,
}),
};
const components = {
Option,
};
function Option(props) {
const { onMouseMove, onMouseOver, ...newInnerProps } = props.innerProps;
return (
<div {...newInnerProps} className="autoselect-options">
{props.children}
</div>
);
}
const ReactSelect = (props) => {
const { label, options, name } = props;
return (
<React.Fragment>
<StyledFormControl>
<StyledAutoSelectInputLabel>
<span>{label}</span>
</StyledAutoSelectInputLabel>
<Select
options={options}
placeholder="Please Select"
valueKey="id"
components={components}
isClearable={true}
styles={stylesReactSelect}
isSearchable={true}
filterOption={createFilter({ ignoreAccents: false })}
{...props}
/>
</StyledFormControl>
</React.Fragment>
);
};
function FormSelectAutoComplete(props) {
const { control } = useFormContext();
const { name, label, options } = props;
const [newData, setNewData] = useState([]);
useEffect(() => {
const newOptions = options.map((data, index) => ({
label: data.label,
value: data.id,
}));
setNewData(newOptions);
}, [options]);
return (
<React.Fragment>
<Controller
as={ReactSelect}
name={name}
control={control}
label={label}
{...props}
options={newData}
/>
</React.Fragment>
);
}
export default FormSelectAutoComplete;
코드를 분해합시다.const stylesReactSelect = {
clearIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
indicatorSeparator: (provided, state) => ({
...provided,
margin: 0,
}),
dropdownIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
placeholder: (provided, state) => ({
...provided,
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
color: state.selectProps.error ? "#f44336" : "rgba(0, 0, 0, 0.54)",
}),
control: (provided, state) => ({
...provided,
borderRadius: 0,
border: 0,
borderBottom: state.selectProps.error
? "1px solid #f44336"
: "1px solid rgba(0,0,0,0.87)",
boxShadow: "none",
":hover": {
borderColor: state.selectProps.error ? "1px solid #f44336" : "inherit",
boxShadow: state.selectProps.error ? "1px solid #f44336" : "none",
},
}),
valueContainer: (provided, state) => ({
...provided,
paddingLeft: 0,
}),
};
const components = {
Option,
};
function Option(props) {
const { onMouseMove, onMouseOver, ...newInnerProps } = props.innerProps;
return (
<div {...newInnerProps} className="autoselect-options">
{props.children}
</div>
);
}
const ReactSelect = (props) => {
const { label, options, name } = props;
return (
<React.Fragment>
<StyledFormControl>
<StyledAutoSelectInputLabel>
<span>{label}</span>
</StyledAutoSelectInputLabel>
<Select
options={options}
placeholder="Please Select"
valueKey="id"
components={components}
isClearable={true}
styles={stylesReactSelect}
isSearchable={true}
filterOption={createFilter({ ignoreAccents: false })}
{...props}
/>
</StyledFormControl>
</React.Fragment>
);
};
FormSelect
과 유사하며 세 가지 주요 아이템name
,label
과options
가 있습니다.options
는reactselect에 표시할 데이터를 포함하는 대상 그룹입니다.function FormSelectAutoComplete(props) {
const { control } = useFormContext();
const { name, label, options } = props;
const [newData, setNewData] = useState([]);
useEffect(() => {
const newOptions = options.map((data, index) => ({
label: data.label,
value: data.id,
}));
setNewData(newOptions);
}, [options]);
return (
<React.Fragment>
<Controller
as={ReactSelect}
name={name}
control={control}
label={label}
{...props}
options={newData}
/>
</React.Fragment>
);
}
FormSelectAutoComplete
구성 요소와 유사합니다. 그 중에서 우리는 FormSelect
방법, useFormContext()
구성 요소와 Controller
대상을 다시 사용합니다.여기서 주의해야 할 점은reactselect의
control
구성 요소에 전달되는 데이터 대상 수조는 대상에 Select
와 label
키를 가지고 있어야 한다는 것이다.아래 코드에서 저는 대상에 이것value
과 label
이 없는 데이터(실제 장면에서 그럴 수 있음)를 목적지에 전달하여 이 요구를 만족시키기 위해 어떤 변경이 필요한지 보여 드리겠습니다.useEffect(() => {
const newOptions = options.map((data, index) => ({
label: data.label,
value: data.id,
}));
setNewData(newOptions);
}, [options]);
데이터 객체에 키 value
및 label
가 포함되어 있으면 이렇게 할 필요가 없습니다.응용 프로그램에서 소비하는 방법을 봅시다
value
.js.다음은 응용 프로그램의 새 코드입니다.회사 명import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
import FormSelect from "./controls/select";
import FormSelectAutoComplete from "./controls/select-autocomplete";
function App(props) {
const methods = useForm();
const { handleSubmit } = methods;
const onSubmit = (data) => {
console.log(data);
};
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={numberData} />
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAuto"
label="Auto Select Numbers"
options={numberData}
isMulti
/>
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
FormSelectAutoComplete
의 변화는 아래의 코드이다<Grid item xs={6}>
<FormSelectAutoComplete
name="selAuto"
label="Auto Select Numbers"
options={numberData}
isMulti
/>
</Grid>
여기에서 우리가 사용하는 것은 App.js
에서 사용하는 것과 같은 numberData
대상 수조이다.reactselect는 대상 수조를 우리가 FormSelect
prop에서 전달하는 데이터로 하기 때문이다.options
선택한 값을 여러 개 표시하려면 prop을 사용합니다.현재 웹 페이지는 다음과 같습니다.
양식 데이터를 작성한 다음 제출 단추를 누르십시오.dev 컨트롤러의 출력을 검사합니다.
Yup 검증
If you have a form, the chance is that 99% of the time you will have some sort of the validation. React Hook Forms provide various ways to do the validation ( Basic Validaiton & Schema Validation ).
우리는 Yup를 사용하여 검증할 것이다.
수정해 봅시다isMulti
.
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
import FormSelect from "./controls/select";
import FormSelectAutoComplete from "./controls/select-autocomplete";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers";
const validationSchema = yup.object().shape({
nameV: yup.string().required("Name Validation Field is Required"),
selV: yup.string().required("Select Validation Field is Required"),
selAutoV: yup.array().required("Multi Select Validation Field required"),
});
function App(props) {
const methods = useForm({
resolver: yupResolver(validationSchema),
});
const { handleSubmit, errors } = methods;
const onSubmit = (data) => {
console.log(data);
};
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
<Grid item xs={6}>
<FormInput
name="nameV"
label="Name with Validation"
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={numberData} />
</Grid>
<Grid item xs={6}>
<FormSelect
name="selV"
label="Numbers with Validation"
options={numberData}
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAuto"
label="Auto Select Numbers"
options={numberData}
isMulti
/>
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAutoV"
label="Auto Select Numbers with Validation"
options={numberData}
isMulti
required={true}
errorobj={errors}
/>
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
새로운 코드 변경 사항을 살펴보겠습니다.
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers";
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import FormInput from "./controls/input";
import FormSelect from "./controls/select";
import FormSelectAutoComplete from "./controls/select-autocomplete";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers";
const validationSchema = yup.object().shape({
nameV: yup.string().required("Name Validation Field is Required"),
selV: yup.string().required("Select Validation Field is Required"),
selAutoV: yup.array().required("Multi Select Validation Field required"),
});
function App(props) {
const methods = useForm({
resolver: yupResolver(validationSchema),
});
const { handleSubmit, errors } = methods;
const onSubmit = (data) => {
console.log(data);
};
const numberData = [
{
id: "10",
label: "Ten",
},
{
id: "20",
label: "Twenty",
},
{
id: "30",
label: "Thirty",
},
];
return (
<div style={{ padding: "10px" }}>
<Button
variant="contained"
color="primary"
onClick={handleSubmit(onSubmit)}
>
SUBMIT
</Button>
<div style={{ padding: "10px" }}>
<FormProvider {...methods}>
<form>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormInput name="name" label="Name" />
</Grid>
<Grid item xs={6}>
<FormInput
name="nameV"
label="Name with Validation"
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelect name="sel" label="Numbers" options={numberData} />
</Grid>
<Grid item xs={6}>
<FormSelect
name="selV"
label="Numbers with Validation"
options={numberData}
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAuto"
label="Auto Select Numbers"
options={numberData}
isMulti
/>
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAutoV"
label="Auto Select Numbers with Validation"
options={numberData}
isMulti
required={true}
errorobj={errors}
/>
</Grid>
</Grid>
</form>
</FormProvider>
</div>
</div>
);
}
export default App;
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers";
App.js
수입const validationSchema = yup.object().shape({
nameV: yup.string().required("Name Validation Field is Required"),
selV: yup.string().required("Select Validation Field is Required"),
selAutoV: yup.array().required("Multi Select Validation Field required"),
});
yup
객체를 만듭니다.yupResolver
은 응용 검증이 필요한 validationSchema
필드의 이름입니다.따라서 사용자 입력 값은 "string"형식 nameV
이 됩니다.필수 필드이기 때문입니다FormInput
.사용자 정의 오류 메시지는 위의 그림과 같이 yup.string()
함수에 전달될 수 있습니다.이와 유사하게,
yup.string().required()
은 required
필드의 이름이며, 드롭다운 목록에서 선택한 값은 "string"형식이기 때문에 selV
사용자 정의 오류 메시지는 위의 그림과 같이 FormSelect
함수에 전달될 수 있습니다.yup.string().required()
은(는) required
필드의 이름이며 선택한 값은 객체 그룹으로 표시됩니다.그래서selAutoV
.사용자 정의 오류 메시지는 위의 그림과 같이 FormSelectAutoComplete
함수에 전달될 수 있습니다. const methods = useForm({
resolver: yupResolver(validationSchema),
});
const { handleSubmit, errors } = methods;
yup.array().required()
대상을 required
함수에 전달합니다. 위 그림과 같습니다.또한 오류 필드와 오류 메시지가 포함된 validationSchema
객체의 yupResolver
객체를 사용합니다.errors
, methods
및 FormInput
, 그리고 두 개의 새로운 도구FormSelect
및 FormSelectAutoComplete
를 추가했습니다.<Grid item xs={6}>
<FormInput
name="nameV"
label="Name with Validation"
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelect
name="selV"
label="Numbers with Validation"
options={numberData}
required={true}
errorobj={errors}
/>
</Grid>
<Grid item xs={6}>
<FormSelectAutoComplete
name="selAutoV"
label="Auto Select Numbers with Validation"
options={numberData}
isMulti
required={true}
errorobj={errors}
/>
</Grid>
검증 오류를 강조하고 해당하는 오류 메시지를 표시하려면 required={true}
, errorobj={errors}
& FormInput
구성 요소를 수정해야 합니다.FormSelect
.required-label span {
color: #f44336;
}
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import TextField from "@material-ui/core/TextField";
import "./index.css";
function FormInput(props) {
const { control } = useFormContext();
const { name, label, required, errorobj } = props;
let isError = false;
let errorMessage = "";
if (errorobj && errorobj.hasOwnProperty(name)) {
isError = true;
errorMessage = errorobj[name].message;
}
return (
<Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
InputLabelProps={{
className: required ? "required-label" : "",
required: required || false,
}}
error={isError}
helperText={errorMessage}
{...props}
/>
);
}
export default FormInput;
우리는 다음과 같은 변경을 했다.const { name, label, required, errorobj } = props;
let isError = false;
let errorMessage = "";
if (errorobj && errorobj.hasOwnProperty(name)) {
isError = true;
errorMessage = errorobj[name].message;
}
FormSelectAutoComplete
중의 FormInput
구성 요소에 도구로 전달된 required
및 errorobj
위에서 사용하고 있습니다.FormInput
필드 이름과 우리가 검증 모드에서 전달한 오류 메시지로 구성되어 있습니다.이 대상은react 갈고리 창에서 만듭니다.위의 코드는 우리가 만든 App.js
& errorObj
폼 구성 요소에서 유사합니다.다음 변경 사항은
FormSelect
구성 요소입니다. <Controller
as={TextField}
name={name}
control={control}
defaultValue=""
label={label}
fullWidth={true}
InputLabelProps={{
className: required ? "required-label" : "",
required: required || false,
}}
error={isError}
helperText={errorMessage}
{...props}
/>
우리는 FormSelectAutoComplete
구성 요소에 다음과 같은 새로운 도구를 추가했다.InputLabelProps={{
className: required ? "required-label" : "",
required: required || false,
}}
error={isError}
helperText={errorMessage}
Controller
, Controller
및 InputLabelProps
도구는 재료 UIerror
에 의해 지정되어 helperText
스타일과 오류 메시지를 표시하는 방법을 제어합니다.TextField
및 TextField
구성 요소에 대해 유사한 코드 변경이 이루어집니다.FormSelect
import React from "react";
import { useFormContext, Controller } from "react-hook-form";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import { StyledInputLabel } from "../../styles";
import FormHelperText from "@material-ui/core/FormHelperText";
const MuiSelect = (props) => {
const { label, name, options, required, errorobj } = props;
let isError = false;
let errorMessage = "";
if (errorobj && errorobj.hasOwnProperty(name)) {
isError = true;
errorMessage = errorobj[name].message;
}
return (
<FormControl fullWidth={true} error={isError}>
<StyledInputLabel htmlFor={name}>
{label} {required ? <span className="req-label">*</span> : null}
</StyledInputLabel>
<Select id={name} {...props}>
<MenuItem value="">
<em>None</em>
</MenuItem>
{options.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
<FormHelperText>{errorMessage}</FormHelperText>
</FormControl>
);
};
function FormSelect(props) {
const { control } = useFormContext();
const { name, label } = props;
return (
<React.Fragment>
<Controller
as={MuiSelect}
control={control}
name={name}
label={label}
defaultValue=""
{...props}
/>
</React.Fragment>
);
}
export default FormSelect;
FormSelectAutoComplete
import React, { useEffect, useState } from "react";
import { useFormContext, Controller } from "react-hook-form";
import Select, { createFilter } from "react-select";
import { StyledFormControl, StyledAutoSelectInputLabel } from "../../styles";
import FormHelperText from "@material-ui/core/FormHelperText";
import "./index.css";
const stylesReactSelect = {
clearIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
indicatorSeparator: (provided, state) => ({
...provided,
margin: 0,
}),
dropdownIndicator: (provided, state) => ({
...provided,
cursor: "pointer",
}),
placeholder: (provided, state) => ({
...provided,
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
color: state.selectProps.error ? "#f44336" : "rgba(0, 0, 0, 0.54)",
}),
control: (provided, state) => ({
...provided,
borderRadius: 0,
border: 0,
borderBottom: state.selectProps.error
? "1px solid #f44336"
: "1px solid rgba(0,0,0,0.87)",
boxShadow: "none",
":hover": {
borderColor: state.selectProps.error ? "1px solid #f44336" : "inherit",
boxShadow: state.selectProps.error ? "1px solid #f44336" : "none",
},
}),
valueContainer: (provided, state) => ({
...provided,
paddingLeft: 0,
}),
};
const components = {
Option,
};
function Option(props) {
const { onMouseMove, onMouseOver, ...newInnerProps } = props.innerProps;
return (
<div {...newInnerProps} className="autoselect-options">
{props.children}
</div>
);
}
const ReactSelect = (props) => {
const { label, options, required, errorobj, name } = props;
let isError = false;
let errorMessage = "";
if (errorobj && errorobj.hasOwnProperty(name)) {
isError = true;
errorMessage = errorobj[name].message;
}
return (
<React.Fragment>
<StyledFormControl>
<StyledAutoSelectInputLabel>
<span className={isError ? "req-label" : ""}>
{label} {required ? <span className="req-label">*</span> : null}
</span>
</StyledAutoSelectInputLabel>
<Select
options={options}
placeholder="Please Select"
valueKey="id"
components={components}
isClearable={true}
styles={stylesReactSelect}
isSearchable={true}
filterOption={createFilter({ ignoreAccents: false })}
error={isError}
{...props}
/>
{isError && (
<FormHelperText error={isError}>{errorMessage}</FormHelperText>
)}
</StyledFormControl>
</React.Fragment>
);
};
function FormSelectAutoComplete(props) {
const { control } = useFormContext();
const { name, label, options } = props;
const [newData, setNewData] = useState([]);
useEffect(() => {
const newOptions = options.map((data, index) => ({
label: data.label,
value: data.id,
}));
setNewData(newOptions);
}, [options]);
return (
<React.Fragment>
<Controller
as={ReactSelect}
name={name}
control={control}
label={label}
defaultValue={[]}
{...props}
options={newData}
/>
</React.Fragment>
);
}
export default FormSelectAutoComplete;
코드를 저장하고 프로그램을 실행하며 제출 단추를 누르십시오.너의 홈페이지는 보기에 비슷하다양식 필드 데이터 미리 채우기
There is always a scenario, where the form fields need to be pre-populated with some data e.g An Edit case of a web form.
React Hook Forms provide us with a method FormSelect
to do that.
setValue("name", "Ammar");
- Here
FormSelectAutoComplete
is the function which accepts two parameters. setValue
is the name of the field, "Ammar" is the value of the field to be set.
-
setValue
function comes from name
object of setValue
function.
const methods = useForm();
const {setValue} = methods;
Github 환매
I have created few more form components like Date Picker, Radio Buttons and Checkbox and have also shown validation for the date as well. Also, all of the code in this tutorial is present in the repo. You can use this repo as a reference or directly use the code in your project.
Repo
공구서류
React Hook Forms provide us with a method
FormSelect
to do that.setValue("name", "Ammar");
FormSelectAutoComplete
is the function which accepts two parameters. setValue
is the name of the field, "Ammar" is the value of the field to be set.setValue
function comes from name
object of setValue
function.
const methods = useForm();
const {setValue} = methods;
Repo
공구서류
만약 제가 본문에서 설명한 내용에 대해 궁금한 점/건의가 있거나 문제가 발견되면 아래의 평론에서 저에게 알려주십시오.시간을 내서 내 글을 읽어 주셔서 감사합니다.
Reference
이 문제에 관하여(React의 양식: React 갈고리 양식 및 재료 UI 및 YUP), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ammartinwala52/forms-in-react-react-hook-forms-with-material-ui-and-yup-4gfb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)