react-hook-form + TS 톺아보기

j_wisdom_h·2023년 12월 3일
1

React

목록 보기
1/4

react-hook-form 공식문서

소개 및 장점

회원가입기능을 구현할때 react-hook-form를 요긴하게 쓸 수 있다.

  1. 더 간결하고 직관적으로 코드를 작성할 수 있다.

    그 이유는 회원가입을 구현할때 여러 입력값에 대한 상태관리를 해줘야하는데 이 경우 복잡해지기 쉽상이고 상태관리에 대한 번거러움이 있기 때문이다.

  2. 입력값의 변화에 따라 전체 폼을 다시 렌더링하는 것이 아니라 필요한 입력 요소만 렌더링한다는 큰 이점이 있다.

  3. 폼 유효성 검사가 내장되어 있어서 사용자의 입력값을 쉽게 유효성을 검증하고 에러를 처리할 수 있다.

즉, react-hook-form은 복잡한 폼 상태를 관리하고 폼을 구현할 때 개발자에게 많은 편의성을 제공하는 데 유용한 도움을 주는 라이브러리다.

설치

npm install react-hook-form
( TS를 지원한다! )

공식 홈페이지에서 사용예에 대한 코드다.

import { useForm, SubmitHandler } from "react-hook-form"


type Inputs = {
  example: string
  exampleRequired: string
}


export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm<Inputs>()
  const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)


  console.log(watch("example")) // watch input value by passing the name of it


  return (
    /* "handleSubmit" will validate your inputs before invoking "onSubmit" */
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* register your input into the hook by invoking the "register" function */}
      <input defaultValue="test" {...register("example")} />


      {/* include validation with required or other standard HTML validation rules */}
      <input {...register("exampleRequired", { required: true })} />
      {/* errors will return when field validation fails  */}
      {errors.exampleRequired && <span>This field is required</span>}


      <input type="submit" />
    </form>
  )
}

key concepts in React Hook Form

1. Register fields

컴포넌트를 훅에 등록(register)한다.
그 결과 해당 컴포넌트의 값이 폼 유효성 검사와 제출 모두에서 사용할 수 있다.

{...register(fields)}

위의 코드에서 찾아보자면 아래와 같다.

 <form onSubmit={handleSubmit(onSubmit)}>
      {/* register your input into the hook 
      by invoking the "register" function */}      
      <input defaultValue="test" {...register("example")} />
</form>

2. Apply validation

기존 HTML 표준과 일치하여 폼 유효성 검사를 간편하게 처리한다.

대표적인 register option

  • required
  • min
  • max
  • minLength
  • maxLength
  • pattern
  • validate
import { useForm, SubmitHandler } from "react-hook-form"

interface IFormInput {
  firstName: string
  lastName: string
  age: number
}

export default function App() {
  const { register, handleSubmit } = useForm<IFormInput>()
  const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data)

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName", { required: true, maxLength: 20 })} />
      <input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} />
      <input type="number" {...register("age", { min: 18, max: 99 })} />
      <input type="submit" />
    </form>
  )
}

이렇게 {}안에 필요한 옵션들을 추가해주면 된다.

더 많은 옵션들과 사용예는 아래 링크에서 자세히 볼 수 있다.
https://react-hook-form.com/docs/useform/register

API

1. useForm

폼 유효성 react-hook

const { register, handleSubmit } = useForm<IFormInput>()

useForm은 폼을 쉽게 관리하기 위한 커스텀 훅이다. 선택적으로 하나의 객체를 인수로 받는다

useForm: UseFormProps

Generic props

  • mode: 제출 전 동작하는 유효성 검사 전략.
  • reValidateMode: 제출 후 동작하는 유효성 재검사 전략.
  • defaultValues: 폼의 기본값.
  • values: 폼 값 업데이트를 위한 반응형 값.
  • resetOptions: 새로운 폼 값 업데이트 시 폼 상태 업데이트를 재설정하는 옵션.
  • criteriaMode: 모든 유효성 검사 오류를 표시할지, 한 번에 하나씩 표시할지 여부.
  • shouldFocusError: 내장된 포커스 관리를 활성화 또는 비활성화하는지 여부.
  • delayError: 오류를 즉시 표시하는 것을 지연하는지 여부.
  • shouldUseNativeValidation: 브라우저 기본 폼 제약 조건 API를 사용하는지 여부.
  • shouldUnregister: 언마운트 후 입력값 등록 해제를 활성화 또는 비활성화하는지 여부.

Schema validation props

  • resolver: 선호하는 스키마 유효성 검사 라이브러리와 통합
  • context: 스키마 유효성 검사에 제공할 컨텍스트 객체

Props

mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'

유효성 검사는 handleSubmit 함수를 호출하여 발생하는 onSubmit 이벤트 중에 발생한다.

2. Register: (name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref })

uncontrolled/controlled inputs을 등록한다

register: (name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref })

const { onChange, onBlur, name, ref } = register('firstName'); 
// include type check against field path with the name you have supplied.
        
<input 
  onChange={onChange} // assign onChange event 
  onBlur={onBlur} // assign onBlur event
  name={name} // assign name prop
  ref={ref} // assign ref prop
/>
// same as above
<input {...register('firstName')} />

3. formState: Object

전체 form State에 대한 정보가 포함되어 있다. 사용자의 상호 작용을 추적하는 데 도움이 된다.

  • isDirty: 사용자가 입력 중 하나를 수정한 후에 true로 설정된다. 폼이 수정되었는지 여부를 파악할 때, 모든 입력 요소의 defaultValues를 useForm에서 가져온다.
  • dirtyFields: 사용자가 수정한 필드들에 대한 객체다.
  • touchedFields: 사용자가 상호작용한 모든 입력 요소를 포함하는 객체이다.
  • defaultValues: useForm의 defaultValues에 설정되거나 reset API를 통해 업데이트된 값.
  • isSubmitted: 폼이 제출된 후에 true로 설정된다. reset 메서드가 호출될 때까지 유지된다.
  • isSubmitSuccessful: 런타임 오류 없이 폼이 성공적으로 제출된 경우 true다.
  • isSubmitting: 폼이 현재 제출 중인 경우 true다. 그렇지 않으면 false이다.
  • isLoading: 현재 비동기 기본값을 로드 중인 경우 true다. 이 속성은 비동기 기본값에만 적용된다.
  • submitCount: 폼이 제출된 횟수이다.
  • isValid: 폼에 오류가 없는 경우 true로 설정된다. setError는 isValid formState에 영향을 주지 않는다. isValid는 항상 전체 폼 유효성 검사 결과를 통해 유도된다.
  • isValidating: 유효성 검사 중인 경우 true로 설정된다.
  • errors: 필드 오류가 있는 객체이다.
import React from "react";
import { useForm } from "react-hook-form";


export default function App() {
  const {
    register,
    handleSubmit,
    // Read the formState before render to subscribe the form state through the Proxy
    formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
  } = useForm();
  const onSubmit = (data) => console.log(data);


  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("test")} />
      <input type="submit" />
    </form>
  );
}

4. Controller: Component, control: Object

  • Controller : wrapper컴포넌트로 외부 제어 컴포넌트(React-Select, AntD, MUI)들과 작업하기 쉽도록 도와준다.
  • control : 이 객체는 컴포넌트를 React Hook Form에 등록하는 메서드를 포함하고 있다.
import ReactDatePicker from "react-datepicker"
import { TextField } from "@material-ui/core"
import { useForm, Controller } from "react-hook-form"


type FormValues = {
  ReactDatepicker: string
}


function App() {
  const { handleSubmit, control } = useForm<FormValues>()


  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <Controller
        control={control}
        name="ReactDatepicker"
        render={({ field: { onChange, onBlur, value, ref } }) => (
          <ReactDatePicker
            onChange={onChange} // send value to hook form
            onBlur={onBlur} // notify when input is touched/blur
            selected={value}
          />
        )}
      />
      <input type="submit" />
    </form>
  )
}

5. useWatch: ({ control?: Control, name?: string, defaultValue?: unknown, disabled?: boolean }) => object

useWatch 함수는 리렌더링이 관련 커스텀 훅 내에서만 일어나도록 제어함으로써 성능 향상을 도모할 수 있다.

import React from "react";
import { useForm, useWatch, Control } from "react-hook-form";

interface FormInputs {
  firstName: string;
  lastName: string;
}

function FirstNameWatched({ control }: { control: Control<FormInputs> }) {
  const firstName = useWatch({
    control,
    name: "firstName", // name을 제공하지 않으면 전체 폼을 감시한다. 또는 ['firstName', 'lastName']와 같이 여러 값 감시 가능
    defaultValue: "default", // 렌더링 전의 기본 값
  });

  return <p>Watch: {firstName}</p>; // firstName이 변경될 때 커스텀 훅 수준에서만 리렌더링된다.
}

function App() {
  const { register, control, handleSubmit } = useForm<FormInputs>();

  const onSubmit = (data: FormInputs) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>First Name:</label>
      <input {...register("firstName")} />
      <input {...register("lastName")} />
      <input type="submit" />

      <FirstNameWatched control={control} />
    </form>
  );
}

useWatch를 사용하여 FirstNameWatched 컴포넌트를 통해 firstName의 변화를 감시하고, 해당 값이 변경될 때 커스텀 훅 수준에서만 리렌더링되도록 한다.

6. watch: (names?: string | string[] | (data, options) => void) => unknown

watch 메서드는 지정된 입력값들을 감시하고 해당 값들을 반환한다. 입력값의 값을 렌더링하거나 조건에 따라 어떤 것을 렌더링할지 결정하는 데 유용하다.

특정한 입력값들을 감시하여 그 값들을 받아올 수 있어서, 해당 값에 따라 조건부로 화면을 렌더링하는 데 활용된다.

import React from "react"
import { useForm } from "react-hook-form"


interface IFormInputs {
  name: string
  showAge: boolean
  age: number
}


function App() {
  const {
    register,
    watch,
    formState: { errors },
    handleSubmit,
  } = useForm<IFormInputs>()
  const watchShowAge = watch("showAge", false) // you can supply default value as second argument
  const watchAllFields = watch() // when pass nothing as argument, you are watching everything
  const watchFields = watch(["showAge", "age"]) // you can also target specific fields by their names


  // Callback version of watch.  It's your responsibility to unsubscribe when done.
  React.useEffect(() => {
    const subscription = watch((value, { name, type }) =>
      console.log(value, name, type)
    )
    return () => subscription.unsubscribe()
  }, [watch])


  const onSubmit = (data: IFormInputs) => console.log(data)


  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register("name", { required: true, maxLength: 50 })} />
        <input type="checkbox" {...register("showAge")} />
        {/* based on yes selection to display Age Input*/}
        {watchShowAge && (
          <input type="number" {...register("age", { min: 50 })} />
        )}
        <input type="submit" />
      </form>
    </>
  )
}

Integrating with services

<Form /> 컴포넌트를 사용하여 라이브러리의 내장 제출 처리 기능을 사용할 수 있다.

 import { Form } from "react-hook-form"

 function App() {
 const { register, control } = useForm()

 return (
 <Form
     action="/api/save" // Send post request with the FormData
       // encType={'application/json'} you can also switch to json object
       onSuccess={() => {
     		alert("Your application is updated.")
     	}}
    	onError={() => {
     		alert("Submission has failed.")
     	}}
     	control={control}
     >
     <input {...register("firstName", { required: true })} />
     <input {...register("lastName", { required: true })} />
     <button>Submit</button>
   </Form>
   )
 }

watch 메서드를 사용하여 showAge에 따라 나이 입력란을 표시하거나 숨기는 예시를 보여준다다.

Schema Validation

스키마 기반의 폼 유효성 검사를 Yup, Zod, Superstruct 및 Joi와 함께 지원한다. useForm에 스키마를 선택적 구성으로 전달하여 스키마에 따라 입력 데이터를 유효성 검사하고 오류 또는 유효한 결과를 반환합니다.

1단계 : yup설치
npm install @hookform/resolvers yup

2단계 : 유효성 검사를 위해 스키마를 준비하고 React Hook Form으로 입력 요소를 등록한다.

import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"


const schema = yup
.object({
  firstName: yup.string().required(),
  age: yup.number().positive().integer().required(),
})
.required()


export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
  	resolver: yupResolver(schema),
  })
  const onSubmit = (data) => console.log(data)

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName")} />
      <p>{errors.firstName?.message}</p>

      <input {...register("age")} />
      <p>{errors.age?.message}</p>

      <input type="submit" />
    </form>
  )
}
profile
뚜잇뚜잇 FE개발자

0개의 댓글