코딩/Today I Learn

React Js Master #7 React-hook-form ,register,watch, ,handleSubmit, formState

코딩쪼렙 2022. 5. 11. 23:49
728x90

 

react-hook-form

 

react에서 form 만들기 편한 방법 .

사용하기 쉬운 유효성 검사를 통해 성능이 뛰어나고 유연하며 확장 가능한 form.

이 것을 사용하지 않으면 많은 input form에 대해 일일이 useState() 사용 해야 함. 

 

1.npm i react-hook-form

 

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

 

3.const { register } = useForm();

useForm의 register을 사용하면 onChange와 관련된 핸들러를 작성할 필요 없다.

 

function ToDoList() {
    const { register } = useForm();
    console.log(register("toDo"));
    return (
        <div>
            <form>
                <input
                    {...register("toDo")}
                    placeholder="Write a to do "
                ></input>
                <button>Add</button>
            </form>
        </div>
    );
}

console.log(register("toDo")) 한 결과 ,toDo라는&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 이름을 갖게되었음&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; register: name, onBlur, onChange, onClick, ref를 return하는 함수

 

 

4.const { watch } = useForm();

useForm의 또 다른 기능 watch.

form내 변화하는 모든 값을 관찰하는 함수 .

console.log하면 toDo라는 이름을 가진 변화된 값들이 나옴.  

 

 

5. 많은 input에 대해 useState를 각각 써 줄 필요가 없음. 

 

function ToDoList() {
    const { register, watch } = useForm();
    console.log(watch());
    return (
        <div>
            <form>
                <input {...register("Email")} placeholder="Email " />
                <input {...register("firstName")} placeholder="firstName" />
                <input {...register("lastName")} placeholder="lastName " />
                <input {...register("ID")} placeholder="ID " />
                <input {...register("password")} placeholder="Password " />

                <button>Add</button>
            </form>
        </div>
    );
}

6.const {handleSubmit}= useForm()

const {register ,handleSubmit}= useForm()

 

const onValid = (data: any) => {
   console.log(data);
 }; 

 

hanldesubmit(onValild , onInValid)

핸들서밋은 두가지 인자를 받는데 하나는 폼이 유효할 때, 유효하지 않을 때 함수이다.

전자는 필수이다.

preventDefault()자동으로 해줌

 

 

                <input
                    {...register("Email", { required: true })}
                    placeholder="Email "
                />
                <input
                    {...register("firstName", { required: true , minLength: 10})}
                    placeholder="firstName"
                />

<input   requrired= true> 같이 html로 작성하면 누군가 소스코드에 수정 할 수 있고 지원하지 않는 브라우저나, 모바일 환경에 있을 수도 있으니 위와 같이 register내에  자바스크립트에서 설정함.

 

sumbit후 자동으로 required이 아닌 input에 자동 포커스

 

7.const { formState }  = useForm()

유효성에 대한 에러를 보여줌

 

function ToDoList() {
    const { register, handleSubmit, formState } = useForm();
    console.log(formState.errors);

id의 minlength에 에러가 생긴걸 보여줌

 

 

메세지도 담아서 보여줄 수 있다.

               <input
                    {...register("password", {
                        required: "password is required",
                        minLength: { // 객체 형태 
                            value: 5,
                            message: "your password is too short",
                        },
                    })}
                    placeholder="Password "
                />

 

 

 

 

register로 직접 등록해야할 이벤트 핸들러 , 유효성 검사등을 함

/* 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");
    }
    console.log("submit");
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input onChange={onChange} value={toDo} placeholder="Write a to do" />
        <button>Add</button>
        {toDoError !== "" ? toDoError : null}
      </form>
    </div>
  );
} */ useForm을 사용하기 전에 쓰던 코드 

 

또다른 vaildation 방법 : 정규표현식

이메일 유효성 검사시에 사용              

  <input
                    {...register("Email", {
                         required: true ,
                        pattern:/^[A-Za-z0-9._%+-]+@naver.com$/
                        })}
                    placeholder="Email "
                />

 

마찬가지로 객체형태로 메세지도 보낼 수 있음

    <input
                    {...register("Email", {
                         required: true ,
                        pattern:{
                            value:/^[A-Za-z0-9._%+-]+@naver.com$/,
                            message: "Only naver.com email allowed"
                        }
                        })}
                    placeholder="Email "
                />

 

에러메세지 화면에 출력하기 

 

function ToDoList() {
    const {
        register,
        handleSubmit,
        formState: { errors },
    } = useForm();
    const onValid = (data: any) => {
        console.log(data);
    };
    return (
        <div>
            <form
                style={{ display: "flex", flexDirection: "column" }}
                onSubmit={handleSubmit(onValid)}
            >
                <input
                    {...register("email", {
                        required: "Email required",
                        pattern: {
                            value: /^[A-Za-z0-9._%+-]+@naver.com$/,
                            message: "Only naver.com email allowed",
                        },
                    })}
                    placeholder="Email "
                />
                <span>{errors?.email?.message}</span>

알아서 메세지가 나타난다.

사용자가 작성하자마자 나타나는 것은 아니고

submit후에 react-form-hook이 작동

 

 

8.interface , generics , default value


interface IForm {
    email: string;
    firstName: string;
    lastName: string;
    ID: string;
    password: string;
}
function ToDoList() {
    const {
        register,
        handleSubmit,
        formState: { errors },
    } = useForm<IForm>({
        defaultValues: {
            email: "@naver.com",
        },
    });

default value 설정한거

정규표현식
^ 문장의 시작

[] : 문자셋 안의 아무문자
+ 하나 또는 하나이상
```
/^[A-Za-z0-9._%+-]+@naver.com$/
/^[A-Za-z0-9._%+-]+@naver.com/g
```
https://www.regexpal.com

React Hook Form (TypeScript)
React Hook Form은 TypeScript로 빌드되었으며, FormData 유형을 정의하여 form 값을 지원할 수 있습니다.
```
type FormData = {
firstName: string;
lastName: string;
};

const { register, setValue, handleSubmit, formState: { errors } } = useForm< FormData >();
```
https://react-hook-form.com/get-started#TypeScript

defaultValues: Record< string, any > = {}
input에 대한 defaultValues는 사용자가 component와 상호 작용하기 전에 component가 처음 렌더링될 때 초기 값으로 사용됩니다.
모든 input에 대한 defaultValues를 빈 문자열이나 null과 같은 정의되지 않은 값으로 설정하는 것이 좋습니다.
https://react-hook-form.com/api/useform#props

 

9.setError 특정 에러 발생시키기 

back에서 에러가 나올 경우 error을 발생 시켜야함 .

직접 에러 발생 시키기

 

const onValid = (data: IForm) => {
        if (data.password1 !== data.password2) {
            setError("password1", { message: "Password are not same" });
        }
    };

 

setError()입력하면 IForm에 있는 항목들만 나온다 따라서 IForm에 새 항목 추가 

interface IForm {
    email: string;
    firstName: string;
    lastName: string;
    ID: string;
    password: string;
    password2: string;
    extraError?: string;
}

    const onValid = (data: IForm) => {
        if (data.password !== data.password2) {
            setError("password", { message: "Password are not same" });
        }
        setError("extraError", { message: "Server offline" });
    };

특정 항목에 대한 error가 아니고 form에 대한 error

 

 

 

<span>{errors?.extraError?.message}</span>

        if (data.password1 !== data.password2) {
            return setError(
                "password1",
                { message: "Password are not same" },
                { shouldFocus: true } //문제가 생긴 곳에 focus 옮기기 password1로 옮겨감.
            );
        }

onValid => password비교하는 부분에서 처음 에러 출력되고, 이 후 Password 에러 출력안되시면 setError앞에 return 해주세요.

 

10.내가 원하는 아무 규칙에따라 validation 하기 validate

예) 사용자가 username을 적는 중에 api에 요청을 보내 이미 있는 username인지 확인하여 알려주기

 

validate:함수로 값을 가지고 value를 인자로 받아 true와 false를 반환함. 

 

firstName 항목에 nico라는 이름을 갖고 있으면 에러

                <input
                    {...register("firstName", { required: "write here", validate: (value)=> !value.includes("nico")})}
                    placeholder="firstName"
                />

 

react-hook-form에서 문자열 반환은 에러메세지를 뜻함. 따라서 다음과 같이 작성가능 

                <input
                    {...register("firstName", {
                        required: "write here",
                        validate: (value) =>
                            value.includes("nico") ? "no nicos allowed" : true,
                    })}
                    placeholder="firstName"
                />

 

validate는 함수로 형식을 갖거나, 객체로 여러가지 조건을 갖을 수 도있다.

ansync 로 값을 요청해서 받아서 서버에 체크해 검사도 가능.

                   validate:{
                            noNico:(value) =>
                            value.includes("nico") ? "no nicos allowed" : true,
                            noNick:(value) =>
                            value.includes("nick") ? "no nick allowed" : true,
                        } 

 

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

 

useForm - register

Performant, flexible and extensible forms with easy-to-use validation.

react-hook-form.com

 

모든 validation은 handlesubmit 호출하면 수행 됨. 

onSubmit이벤트에 등록해야함. 인자는 딱 한개를 받는데 바로 onValid 함수 (formdata가 유효할 때 호출되는 함수 .)

    

const onValid = (data: IForm) => {
        if (data.password !== data.password2) {
            return setError(
                "password",
                { message: "Password are not same" },
                { shouldFocus: true }
            );
        }
        setError("extraError", { message: "Server offline" });
    };

 

 return (
        <div>
            <form
                style={{ display: "flex", flexDirection: "column" }}
                onSubmit={handleSubmit(onValid)}
            >'

11. const{setValue} = useForm();

onSubmit 후 value 비우고싶을 때 

 

 

간단한 todoList

 

import React from "react";
import { useForm } from "react-hook-form";
interface IForm {
    toDo: string;
}
function ToDoList() {
    const {
        register,
        handleSubmit,
        formState: { errors },
        setValue,
    } = useForm<IForm>();
    const handleValid = (data: IForm) => { //form이 유효하면 submit되고 
        console.log("add to do ", data.toDo); 
        setValue("toDo", ""); //toDo에 있는 value가 ""로 변경됨
    };
    return (
        <div>
            <form onSubmit={handleSubmit(handleValid)}> //
                <input
                    {...register("toDo", {
                        required: "please write to Do",
                    })}
                    placeholder="write a to do"
                />
                <button>Add</button>
                <span>{errors?.toDo?.message}</span>
            </form>
        </div>
    );
}

export default ToDoList;