To Do List #1 React Hook Form

Leesu·2022년 11월 29일
0

잊기 전에 복습 들어간다~~


React Hook Form

React Hook Form은 React 내에서 Form을 쉽게 제어하고 손쉽게 유효성 검사를 처리하도록 도와주는 라이브러리.
다른 종속성이 없는 최소한의 라이브러리로 구성되어 있어 성능이 뛰어나고 사용이 간편하다.

  • 우선 React Hook Form 없이 <form>,<input>,<button> 으로 구현해보기
- app.tsx

function App() {
  return (
    <>
      <GlobalStyle />
      <TodoList />
    </>
  );
}
- ToDoList.tsx

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 LONGER');
    }
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input onChange={onChange} value={toDo} placeholder="Write a to do" />
        <button>Add</button>
        <toDoError !== "" ? toDoError : null }
      </form>
    </div>
  );
}
  • state를 선언하고, 각 입력 필드에 event를 연결해 value를 받아왔는데..
  • 지금은 간단한 input 이 한 개만 있으니 이정도지만,
    만약 input 이 하나가 아니라 여러개라면 ? ;;

React Hook Form 으로 구현

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

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

register

  • ref로 사용되는 함수로 입력 필드를 React Hook Form에 등록하고 변경 사항에 대해 값을 추적
  • {...register("사용하고 싶은 이름")} 입력 필드에는 name 속성이 있어야 하며 해당 값은 고유해야 함

handleSubmit

  • form을 서버로 제출할 때 사용되며, 함수를 인자로 받고 그 함수에 data 라는 인자를 넘겨준다.
  • 2개의 인자를 받는데, 첫 번째는 데이터가 유효할 때(form 제출 성공 시) 호출되는 함수로, 필수임
    두 번째는 데이터가 유효하지 않을 때 호출되는 함수로, 필수는 아니다.

watch

  • form의 입력값을 추적

  • React hook form 을 사용하면 valueonChange로 각 입력 필드에 대한 처리를 추가할 필요가 없고, state를 직접 관리할 필요가 없다!

function ToDoList() {
  const { register, watch, handleSubmit } = useForm();
  return (
    <div>
      <form>
        <input {...register("email")} placeholder="Email" />
          // → ... : 기존의 register 함수가 반환하는 객체들을 input 에 props 로 줄 수 있다.
        <input {...register("firstName")} placeholder="First Name" />
        <input {...register("lastName")} placeholder="Last Name" />
        <input {...register("username")} placeholder="Username" />
        <input {...register("password")} placeholder="Password" />
        <input {...register("password1")} placeholder="Password1" />
        <button>Add</button>
      </form>
    </div>
  );
}

Validation

  • handleSubmit 으로 기존 코드의 validation, preventDefault 를 대체해줄 수 있다?
const { register, watch, handleSubmit } = useForm();
const onValid = (data:any) => {
	console.log(data);
}
return (
    <div>
      <form onSubmit={handleSubmit(onValid)}>
        <input {...register("email")} placeholder="Email" />
  • 유효성 검사는 handleSubmit 함수가 실행 될 때 진행되는데,
    위의 경우 데이터가 유효하므로 console 에 data 가 출력되지만,
    유효성 검사가 실패하면 해당 입력 필드에 자동으로 focus 처리,
    errors가 하나라도 존재할 경우 form 제출을 안한다.
  • 어떤 error 가 발생한건지 확인하고 싶다면 formState 를 사용하면 된다.
<input {...register("email", {
	required: true, 
    minLength: 10}  <<<----
	)} placeholder="Email" />
<input {...register("firstName", {
	required:"Frist Name is required!" }  <<<----
    )} placeholder="First Name" />
<input
  {...register("password1", {
    required: "Password is required", <<<-----
    minLength: {
      value: 5,
      message: "Your password is too short.",
    },
  })}
  placeholder="Password1"
/>
  • 방법은 두 가지가 있는데...
  • 기본으로 required: true 라고 주어도 되지만,
    error 발생 시 조금 더 구체적으로 보고싶다면 required: "Password is required" 메시지로 전달해줘도 된다.
  • minLength 의 경우에도 최소 숫자만 적거나(값을 즉시 보내거나),
    객체로 보내서 객체 안에서 값도 보내고 메시지도 보낼 수 있다.

  • 유저에게 에러 메시지를 화면에서 보여줄 수도 있다.
const { register, watch, handleSubmit, formState : {errors} } = useForm();

<input .... />
<span>
	{errors?.email?.message}
</span>

  • 위와 같이 에러 메시지를 띄워줄 수 있다!
  • 당연히 required: true 라고 적어줬다면, 띄워지지 않는다. 무조건 메시지가 있어야만 에러 메시지가 띄워진다.

defaultValues

  • 기본값을 넣어줄 수 있다.
  • 우선, TypeScript 에게 우리의 form 이 어떻게 생겼는지 알려주자.
interface IFrom {
	email : string;
    firstname : string;
    lastername : string;
    username : string;
    password : string;
    password1 : string;
}

...

const { register, watch, handleSubmit, formState : {errors} } = useForm<IForm>();

// 만약 여기있는 항목들 중에서 필수항목이 아닌게 있다면 ? 을 꼭 붙이기.
  • type 을 알려주었기 때문에, 기본값을 설정할 수 있다.
const { register, watch, handleSubmit, formState : {errors} } 
	= useForm<IForm>({
    	defaultValues : {
        	email: "@naver.com;
        }
    });
  • placeholder 처럼, email 칸에 "@naver.com"을 기본값으로 넣어줄 수 있다.

Custom Validation

  • setError 는 특정 값에 직접 에러를 발생시킬 수 있다.
const onValid = (data: IFrom) => {
	if (data.password!== data.password1) {
    	setError("password1", {
        	meesage:"password are not the same",
        	shouldFocus: true,	
        })
    }
}
  • 패스워드와 패스워드 확인란이 다를 경우 위에 설정한 에러 메시지가 확인되며, form 이 제출되지 않는다.

  • 또한, shouldFocus를 설정했으므로 password1 에 오류가 있다면 form 의 커서가 password1 으로 옮겨질 것.

  • 내가 원하는 validation 을 추가하려면

	... { required: "write here", validate: (value) => ture }
  • validate 는 함수를 값으로 가지며, 인자로 항목에 쓰여지고 있는 값을 받는다.
    반환값은 boolean or string 문자열
  • first name 이 "nico" 인 사람은 form 제출이 불가하도록 만들어보자.
validate : (value) => !value.includes("nico"),
  • nico 가 포함되어있다면 fasle 를 출력하며 form 제출이 불가,
    포함되어있지 않다면 true 를 출력하며 form 제출이 가능해진다.
validate : (value) => value.includes("nico") ? "no nicos allowed" : true, 
  • nico 가 포함되었을 경우 지정한 에러 메시지가 띄워지며, 포함되지 않았을 경우 통과.
  • 만약 조건이 1개 이상일 경우 객체 리터럴로 보내주면된다.
validate : {
	...
}

React Hook Form 을 사용하여 기존 코드 변경하기

interface IForm {
  toDo: string;
}

function ToDoList() {
  const { register, handleSubmit, setValue } = useForm<IForm>();
  const handleValid = (data: IForm) => {
    setValue("toDo", "");
  };
  
  return (
    <div>
  	  <form onSubmit={handleSubmit(handleValid)}>
        <input
			{...register("toDo", {
            required: "Please write a To Do",
         })}
          placeholder="Write a to do"
        />
        <button>Add</button>
      </form>
    </div>
  );
}

export default ToDoList;
profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글