[React] react-hook-form의 useState(), Validation 대체

오트밀·2022년 2월 15일
0
post-thumbnail

form으로 많은 입력값을 받을때 유용하게 활용할 수 있는 라이브러리다.

useState()대체

register, watch

기존의 코드

react에서 useState로 입력값을 받는 코드

import React, { useState } from 'react';

...

function ToDoList() {
  const [toDo, setToDo] = useState('');
  const [toDoError, setToDoError] = useState('');
  const onChange = (event: React.FormEvent<HTMLInputElement>) => {
    const {
      currentTarget: { value },
    } = event;
    setToDoError('');
    setToDo(value);
  };
  const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (toDo.length > 10) {
      return setToDoError('to do should be shorter');
    }
    console.log('submit');
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input onChange={onChange} value={toDo} placeholder="write a todo" />
        <button>Add</button>
        {toDoError !== '' ? toDoError : null}
      </form>
    </div>
  );

input박스마다 state, 에러 state를 모두 작성한다. 게다가 만약 회원가입 화면과 같이 input값이 많아진다면 validation도 필요하다.

그렇게 된다면 코드가 너무 길어지는데 react-hook-form을 사용하면 input이 증가하더라도 그에 따라 state를 늘려갈 필요가 없다.

수정된 코드

npm install react-hook-form
import { useForm } from 'react-hook-form';

...

function ToDoList() {
  const { register, watch } = useForm();
  console.log(register('todo'));
  console.log(watch());
  

  return (
    <div>
      <form>
      	<input {...register('todo')} placeholder="write a todo" />
		//input에 prop이 todo인 register가 반환하는 객체를  넣는다.
        <input {...register('email')} placeholder="Email" />
        <input {...register('firstName')} placeholder="Email" />
        <input {...register('lastName')} placeholder="Email" />
        <input {...register('password')} placeholder="Email" />
        <input {...register('passwordConfirm')} placeholder="Email" />
        <button>Add</button>
      </form>
    </div>
  );
}

react-hook-form의 register 함수는 앞의 onChange이벤트 핸들러, onChange 이벤트를 대신한다.

register함수는 onBlur, onChange, ref, name 이 있다.

watch 함수는 모든 value를 출력한다.

console.log(watch())를 작성하면 {todo : '... '}으로 입력된 데이터 값이 실시간으로 출력된다.

이 코드는 입력값이 많을때 유용하다. input 태그가 많아지면 보통 그에 따라 state 가 증가하는데 hook form을 사용하면 기존의
const { register, watch } = useForm(); 만으로 해결할 수 있다.


https://react-hook-form.com/api/useform/register#main
https://react-hook-form.com/api/useform/watch#main


Validation

handleSubmit

handleSubmit은 두개의 인자를 받는다.

https://react-hook-form.com/api/useform/handlesubmit/

그림의 설명과 같이 submitHandler는 데이터가 유효할때 호출되는 함수, SubmitErrorHandleer는 데이터가 유효하지 않을때 호출되는 함수다.


function TodoList() {
  const { register, handleSubmit } = useForm();
  const onValid = (data: any) => {
    console.log(data);
  };

  return (
    <div>
      <form onSubmit={handleSubmit(onValid)}>
        <input {...register("todo")} placeholder="write todo" />
        <input {...register("email")} placeholder="email" />
        <input {...register("name")} placeholder="name" />
        <button>Add</button>
      </form>
    </div>
  );
}

이때 input 태그 안에 required:true를 추가하면 그 태그의 데이터가 필수값이 돼서 데이터가 입력되지않으면 submit되지않는다.

 <input {...register("todo")} required={true} placeholder="write todo" />

위의 코드와 같이 required 속성을 태그에 넣을 수도 있지만

        <input
          {...register("todo", { required: true })}
          placeholder="write todo"
        />

required 속성을 register 함수 내부에 넣어주면 자바스크립트에서 validation을 해서 required 속성을 지원하지 않는 브라우저나 모바일에서도 동작 가능하다. 그리고 html을 수정해서 required 속성을 지우고 데이터를 등록하는 걸 막을 수 있다.

또 다른 장점은 required:true인 input box가 값이 빈채로 submit을 하면 빈 input box로 커서를 옮겨준다.


required 뿐만아니라 min, max, minLength 등 속성을 추가해서 validation이 가능하다.

+) useForm의 setError함수를 사용해 조건에 맞지 않을 때 에러를 출력할 수도 있고
onValid는 interface IForm을 받아서 데이터 타입검사를 할 수 있다.

  const {
    register,
    handleSubmit,
    formState: { errors },
    setError,
  } = useForm<IForm>({
    defaultValues: {
      email: '@naver.com',
    },
  });
interface IForm {
  email: string;
  firstName: string;
  lastName: string;
  username?: string;
  password: string;
  passwordConfirm: string;
}

  const onValid = (data: IForm) => {
    if (data.password !== data.passwordConfirm) {
      setError(
        'password',
        { message: 'password are not the same' },
        { shouldFocus: true }
      );
    }
  };

password와 passwordConfirm이 같은 값이 아닐 경우

이런 경고가 뜬다

formState


const { register, handleSubmit, formState } = useForm();

console.log(formState.errors);

  return (
    <div>
      <form onSubmit={handleSubmit(onValid)}>
        <input
          {...register("todo", { required: true, minLength: 10 })}
          placeholder="write todo"
        />
        <button>Add</button>
      </form>
    </div>
  );
}

위의 코드에 formState를 추가하면 input box에 입력한 데이터가 필수조건에 맞지 않을때 오류를 출력한다.

        <input
          {...register("todo", {
            required: true,
            minLength: { value: 10, message: "your input is too short" },
          })}
          placeholder="write todo"
        />

또 input box 속성을 이런식으로 작성해서 오류가 발생하면 메세지까지 띄워줄 수 있다.

validate - register()

<input
          {...register('firstName', {
            required: true,
            validate: {
              noOatmeal: (value) =>
                value.includes('oatmeal') ? 'NO oatmeals allowed' : true,
              noNick: (value) =>
                value.includes('nick') ? 'NO Nicks allowed' : true,
            },
          })}
          placeholder="firstName"
        />

inputbox의 register 함수에 validate 속성을 넣는다. 위와 같이 한개 이상의 validation조건을 넣을 수 있다.

https://react-hook-form.com/get-started#applyvalidation

profile
루틴을 만들자

0개의 댓글