React JS master #5.2 React-Hook-Form

김아현·2022년 10월 6일
0

React-web

목록 보기
3/9

React Hook Form

React JS에서 Form을 관리하기 위한 라이브러리
회원가입 시 이름, 이메일, 성별, 아이디, 비밀번호 등등 많은 input이 필요한 상황에서 data validation과 state 관리를 위해서 데이터 속성 값만큼의 input 컴포넌트가 필요하게 된다.

npm install react-hook-form을 통해 form component를 관리하고, onChange 함수나 onSubmit, State를 트래킹한다. 서비스는 기본적으로 회원가입이나 로그인, 아이디 찾기 등에서 form을 사용하고 있으며, 이런 form을 사용하기 편하도록 react-hook-form 라이브러리를 사용한다.

//ToDoList.tsx
...
  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("Error");
    }
    console.log(toDo);
  };
...

기존의 form validation은 위 코드와 같이, form component 마다 state, function, event에 따른 Error case를 직접 하나하나 작성해야 했다. React Hook Form을 사용하면, 이런 state 관리와 function 작성, validation을 한 번에 처리할 수 있다. 사용 방법은 간단하다.

  1. import { useForm } from "react-hook-form"을 통해 React Hook Form을 import한다.
    2.필요한 Form function을 Component안에 선언하고 사용한다.

#1 Function - Register

Form function 중에서, 'register'함수를 사용해보자.

//ToDoList.tsx
import { useForm } from "react-hook-form";
...
const { register } = useForm();
console.log(register("toDo"));
...

아래 이미지는 위 코드 실행 결과가 출력된 console message이다. register function은 parameter를 string 타입으로 받아 객체를 만든다. 만들어진 객체는 name, onChange, onBlur, ref의 property를 가진다.
코드 실행 결과

javascript es6 spread 문법을 통해 컴포넌트에게 register 함수가 반환하는 객체를 props로 전달하여 컴포넌트를 렌더링할 수 있다. spread 문법으로 아래와 같이, tag안에 바로 객체를 생성할 수 있다.

//ToDoList.tsx
...
return (
    <div>
      <form>
        <input {...register("toDo")} placeholder="write a to do" />
        <button type="submit">Add</button>
      </form>
    </div>
  );
}

이제 React Hook Form의 다른 기능 몇 가지들을 더 추가해보자.


#2 Function - watch

watch는 register function이 작동하고 있는 form안에서 input이 어떻게 변화하는지 상태를 tracking해준다. 아래와 같은 코드를 작성해보자.

// ToDoList.tsx
...
const {register, watch, handleSubmit} = useForm(); 
console.log(watch());
...

watch function을 사용하면 따로 컴포넌트에 객체 속성을 작성하거나 할 필요 없이 console에 아래와 같이 출력되며, 정상적으로 input value를 tracking 중인 것을 확인할 수 있다.


#3 Function - handleSubmit

handleSubmit function은 onSubmit event 대신에 쓰이며, validation과 관련있다. form 컴포넌트에 onSubmit={handleSubmit(onValid)} 문법을 통해서 쓰인다.

handleSubmit은 register function이 등록된 객체로부터 valid option 객체를 받아 그 내용을 바탕으로 유효성을 검사한다. 자세한 option의 사용법은 링크를 참고하자.

const {register, handleSubmit} = useForm();  
  const onValid = (value: any) => {
    console.log(value);
  }; 
  return (
    <div>
      <form style={{display:"flex", flexDirection:"column"}} onSubmit={handleSubmit(onValid)}>
        <input {...register("name", {required:true , minLength: 3, maxLength:20})} placeholder="name" />
        <input {...register("email", {required:true , minLength: 12, maxLength:40})} placeholder="email" />
        <input {...register("id", {required:true , minLength: 5, maxLength:20})} placeholder="id" />
        <input {...register("password", {required:true , minLength: 3, maxLength:20})} placeholder="password" />
        <button type="submit">Add</button>
      </form>
    </div>
  );
}

React Hook Form의 장점 중 하나는 자연스러운 유효성 검사를 통해, 제출한 input중 validation option을 통과하지 못한 input을 자동으로 focus하여 유저의 사용성을 증가시킨다는 점이다.

validation으로 minLength 옵션을 통과하지못한 input을 focus 한다.

#4 Property - formState

formState는 form value가 validation에 통과하지 못할 경우, error 객체를 반환하며, 어떤 input이 어떠한 option에 통과하지 못한 것인지 그 이유까지 error message의 type으로 함께 반환하여 준다.

이미지 상에 보이는 것처럼, 각 input 객체에서 error type과 함께 메세지를 출력했고 이를 위해 아래와 같이 코드를 작성했다. 이 message를 User에게 전달하여보자.

  const {register, handleSubmit, formState } = useForm(); 
  console.log(formState.errors);
  const onValid = (value: any) => {
    console.log(value);
  }; 
  return (
    <div>
      <form style={{display:"flex", flexDirection:"column"}} onSubmit={handleSubmit(onValid)}>
        <input {...register("name", {required:'Please write valid name' , minLength: {value : 10, message :"min length is  3"}, maxLength:20})} placeholder="name" />
        <input {...register("email", {required:'Please write valid email', minLength: 12, maxLength:40})} placeholder="email" />
        <input {...register("id", {required:'Please write valid id' , minLength: 5, maxLength:20})} placeholder="id" />
        <input {...register("password", {required:'Please write valid password' , minLength: 3, maxLength:20})} placeholder="password" />
        <button type="submit">Add</button>
      </form>
    </div>
  );
}

#5 Property - Pattern (Regular Expression)

register 객체의 속성으로 주어지는 pattern은 정규 표현식으로, 정규표현식은 문자 파싱의 원리를 이용하여 validation에 필요한 문자열의 형태를 전달하는 하나의 문법이다.

...
        <input
          {...register("email", {
            required: "Please write valid email",
            pattern: {
              value: /^[A-Za-z0-9._%+-]+@naver.com$/,
              message: "only allows @naver.com",
            },
            minLength: 12,
            maxLength: 40,
          })}
          placeholder="email"
        />
...

위 처럼, register 객체에 속성으로 pattern을 작성하여 주면 되고, 링크를 통해 정규 표현식 작성과 테스트를 더 자세히 살펴볼 수 있다.
또한, pattern도 다른 property들과 마찬가지로 객체값을 가질 수 있고, 객체는 value와 error message를 가진다.


#6 Return Property as a Component

이제 마지막으로, 화면에 Form이 return하는 property를 띄워보자. 이번엔 formState를 통해 반환되는 error message를 화면에 띄울 것인데, useForm을 사용해 formState property를 가져올 때, 해당 property가 가진 errors 객체를 분할하여 가져와 보자. 이때 최신 버전 타입스크립트를 사용하며 주의할 점은 Form의 타입 인터페이스를 선언해서, Component rendering에 문제가 없도록 해야한다.

...
const {register, handleSubmit, formState : {errors} } = useForm<IFormData>(); 
...
// Interface 선언
type IFormData = {
  errors: {
    email:{ message : string; };
  };
  name : string;
  email: string;
  id: string;
  password: string;
  password_confirmation: string;
}
...
// UI에 띄우기 
  return (
    ...
      <span>{errors?.email?.message}</span>
    ...
    )

#7. Custom Validation

Form에 제출된 비밀번호의 유효성 검사를 진행해보자. 이를 위해 진행하는 순서는 아래와 같다.

  1. 유효성 검사 함수인 onValid의 파라미터로 (data : IFormData) 를 받는다.
  2. 함수안에 password가 일치하는지 검사하는 코드를 작성한다.

password validation 코드는 아래와 같다.

// ToDoList.tsx
...
  const onValid = (value: IFormData ) => {
    if(value.password !== value.password_confirmation){
      setError("password", {message: "password are not the same"}, {shouldFocus: true});
    }
  };
...
	<form>
  		...
		<input
          {...register("password", {
            required: "Please write valid password",
            minLength: 3,
            maxLength: 20,
          })}
          placeholder="password"
          />
        <input
          {...register("password_confirmation", {
            required: "Please write valid password",
            minLength: 3,
            maxLength: 20,
          })}
          placeholder="password"
          />
          <span>{errors?.password?.message}</span>
        <button type="submit">Add</button>
	</form>
...
profile
멘티를 넘어 멘토가 되는 그날까지 파이팅

0개의 댓글