React의 양식: React 갈고리 양식 및 재료 UI 및 YUP

React에서는 폼을 작성할 수 있는 방법이 많습니다. 일부는 Formik, Redux form 같은 라이브러리를 사용하거나 간단한 방식으로 처음부터 모든 내용을 작성하는 것을 좋아합니다.폼 라이브러리를 사용하는 장점은 검증, 단일 대상에서 전체 폼 데이터를 얻고 더 적은 코드를 작성하는 등 흔히 볼 수 있는 많은 폼 기능을 처리할 수 있다는 것이다.
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 폼을 포함하고 사람들이 쉽게 그것을 인용하거나 그들의 프로젝트에 집적할 수 있다

카탈로그


이 문장은 매우 길다.그래서 나는 문장을 몇 부분으로 나누었다
  • Initial setup

  • Basic form element binding with React Hook Form
  • TextField
  • Select
  • Multi-Select with Autocomplete (React-Select)
  • Validation with Yup
  • Pre populating form field data
  • Github repo
  • References
  • 초기 설정

    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,

    1. We have to register each form field that we use. This helps in form submission and validation.
    2. 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

    1. 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.
    2. 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,
      }),
    };
    
  • 이상의 코드는 스타일 변경일 뿐입니다.앞서 언급한 바와 같이 디자인의 일치성을 유지하기 위해 외관과 느낌을 재료 UI 선택과 유사하게 하기 위해서입니다.본 link의reactselect의 전체 스타일 안내서를 참조할 수 있습니다
  • const components = {
      Option,
    };
    
    function Option(props) {
      const { onMouseMove, onMouseOver, ...newInnerProps } = props.innerProps;
      return (
        <div {...newInnerProps} className="autoselect-options">
          {props.children}
        </div>
      );
    }
    
  • 대량의 데이터 (100여 개의 데이터 대상) 가 있는 경우 상기 코드는 성능을 향상시킬 수 있습니다
  • 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>
      );
    };
    
  • 탭과 반응 선택 구성 요소가 있는 UI 섹션입니다.FormSelect과 유사하며 세 가지 주요 아이템name,labeloptions가 있습니다.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 구성 요소에 전달되는 데이터 대상 수조는 대상에 Selectlabel 키를 가지고 있어야 한다는 것이다.아래 코드에서 저는 대상에 이것valuelabel이 없는 데이터(실제 장면에서 그럴 수 있음)를 목적지에 전달하여 이 요구를 만족시키기 위해 어떤 변경이 필요한지 보여 드리겠습니다.
  • useEffect(() => {
        const newOptions = options.map((data, index) => ({
          label: data.label,
          value: data.id,
        }));
        setNewData(newOptions);
      }, [options]);
    
    데이터 객체에 키 valuelabel 가 포함되어 있으면 이렇게 할 필요가 없습니다.
    응용 프로그램에서 소비하는 방법을 봅시다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는 대상 수조를 우리가 FormSelectprop에서 전달하는 데이터로 하기 때문이다.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";
    
  • 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, methodsFormInput, 그리고 두 개의 새로운 도구FormSelectFormSelectAutoComplete를 추가했습니다.
  • <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
  • 색인을 만듭니다.css 파일은 컨트롤의 입력 폴더에 있습니다 (컨트롤 -> 입력 -> 인덱스.css).지수css에는 다음 코드가 포함됩니다.
  • .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 구성 요소에 도구로 전달된 requirederrorobj 위에서 사용하고 있습니다.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, ControllerInputLabelProps 도구는 재료 UIerror에 의해 지정되어 helperText 스타일과 오류 메시지를 표시하는 방법을 제어합니다.TextFieldTextField 구성 요소에 대해 유사한 코드 변경이 이루어집니다.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 Form
  • Material UI
  • Yup
  • React Select
  • Material UI Pickers
  • Styled Components

  • 만약 제가 본문에서 설명한 내용에 대해 궁금한 점/건의가 있거나 문제가 발견되면 아래의 평론에서 저에게 알려주십시오.시간을 내서 내 글을 읽어 주셔서 감사합니다.

    좋은 웹페이지 즐겨찾기