State Management(2)

초연2e·2022년 10월 1일
0

MUTSA_Front.archive

목록 보기
5/16

Setup - Form 형성

import { useState } from "react";

function ToDoList(){
    const [toDo, setToDo] = useState("");
    const onChange = (event:React.FormEvent<HTMLInputElement>) => {
        const {currentTarget : {value},
    } = event;
    setToDo(value);
    };
    const onSubmit = (event:React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        console.log(toDo);
    }
    return <div>
        <form onSubmit={onSubmit}>
            <input value={toDo} onChange={onChange} placeholder="Write a to do"/>
            <button>Add</button>
        </form>
    </div>
}

export default ToDoList;

일단 기본적으로 form을 만들어준다.
typescript에서 form은 이렇게 해주면 됐었지~.~

약간 형식?같은거인듯.. 걍 저렇게 하면 됨
저렇게 해주면 우리가 submit하는 값이 콘솔에 찍힌다.ㅇㅇ

그런데 코드가 너무 길고 지루하다,,
만약 input이 여러개 있다면 우리는 onChange도 여러개 만들어줘야한다.

그래서 react-hook-form을 사용하면
이 모든 걸 한 줄의 코드로 작성할 수 있다.




React Hook Form

기본 setting

리액트에서 form을 가장 쉽게 관리할 수 있게 해준다.
큰 규모의 form을 다룰 때 매우 유용.

설치
터미널에 npm install react-hook-form 입력

우리는 useForm이라는 hook을 사용할 것이다.
import 해주자!





register

register 함수가 위의 모든 것을 대체해줄 것이다.

    const {register} = useForm();
    console.log(register("toDo"));

이렇게 해주고 콘솔에 찍힌 것을 확인해 register함수를 호출했을 때 생기는 일을 알아보자.

짠~~~ 이런 객체를 만들어준다.
onBlur, onChange, ref, name이 생긴다.

        <form>
            <input {...register("toDo")} placeholder="Write a to do"/>
            <button>Add</button>
        </form>

이제 이렇게 해주면
register 함수가 반환하는 객체가 input에 props로 전달된다.
useForm을 이용한 한 줄의 코드로 onChange, value, useState가 모두 대체되었다.




watch

여기서 이제 추가로 useForm을 한 번 더 사용해준다.
이번에는 watch를 사용해보자.
watch는 form의 입력값들의 변화를 관찰할 수 있게 해주는 함수이다.

    const {register, watch} = useForm();
    console.log(watch());

해주면


이렇게 됨.

이런 react hook form은 input이 여러개 있을 때 매우매우 효과를 발휘한다고 함!




Form Validation

handleSubmit

handleSubmit으로 onSubmit을 모두 대체할 수 있다.
handleSubmit이 validation을 담당하게 된다,,
preventDefault도 담당하고,,, 다 해준다.

form의 onSubmit 이벤트 안에 handleSubmit을 호출하고, handleSubmit은 2개의 인자를 받는다.

하나는 데이터가 유효할 때 호출되는 함수, 하나는 유효하지 않을 때 호출되는 함수이다.
후자(onInValid)는 필수가 아니지만, 전자(onValid)는 필수임.

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

function ToDoList(){
    const {register, handleSubmit} = useForm();
    const onValid = (data:any) => {
        console.log(data);
    }
    return (
    <div>
        <form onSubmit = {handleSubmit(onValid)}>
            <input {...register("Email")} placeholder="Email"/>
            <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>
    )
}
export default ToDoList;

이렇게 해주고 각 정보를 채워서 Add 버튼을 누르면

wow 이렇게된다. 매우 간단하고 대박임
유저가 submit을 하면 handleSubmit이 validation과 해야할 일을 모두 마치고 데이터가 유효할 때만 함수를 호출한다. wowwww


이제 form이 유효하지 않을 때를 생각해보자.

register 함수 안에 {required : true}를 추가해주면 HTML에 의지하는 것이 아닌, 자바스크립트에서 validation을 할 수 있게 된다.

저렇게 해주면 빈 input이 있는데 Add를 눌렀을 때,
자동으로 비어있는 input에 마우스 커서를 focus해준다🤭🤭🤭🤭
(당연히 submit되지 않는다.)

추가로 register 함수에 minLength만 추가해준다면
텍스트 길이가 그 설정값을 넘지 않을 때를 알아서 validation 해준다.



아 추가로 required에 true를 설정해주면 그 값이 필수라는 것을 설정해준 것이고,
required에 메세지를 넣어준다면 유저에게 보여줄 화면에 나올 에러 객체에 들어가게 된다.

minLength도 마찬가지로 그냥 최소 글자수를 보낼 수도 있고, 객체를 보내서 value값과 메세지를 전달할 수 있다.



진짜 매우 대박인 기능




formState

useFormformState를 사용해보자.
console에 formState.errors를 찍어보면...
알아서 에러를 표시해준다. omg
어디서 에러가 났는지, 어떤 에러가 난건지 알려준다.



정규식 검사 & 에러 출력


register 함수에 pattern을 추가해주자
pattern에는 정규식을 복붙해주자

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

자 이런식으로 해주고 콘솔에서 한 번 확인해보자.

email칸에 @naver.com 형식이 아닌 값을 넣어서 Add를 클릭해보면 콘솔창에는 Only naver.com emails allowed 라는 메세지가 출력된다.
물론 error type은 pattern이 되겠지?

이제 에러를 콘솔에서만 보지 말고 유저화면에 보여줘보자


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

이러면 이제 이메일이 @naver.com 형식으로 작성되지 않았을 경우 message를 화면에 출력한다.

다른 input들도 다 같은 방식으로 작성해주면 된다.

interface설정도 추가로 해주면 되겠다.

    const {
        register,
        handleSubmit,
        formState: { errors },
      } = useForm<IForm>({
        defaultValues: {
          email: "@naver.com",
        },
      });

이런식으로 default값도 설정해줄 수 있다.




setError

password 일치 확인


password와 password1의 값이 다르면 에러를 출력해보자.
비밀번호 확인 기능이 되겠다.


data 형식을 IForm(interface이름)으로 바꿔주고

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

해주자.
이렇게 했을 때 비밀번호가 일치하지않으면

이런식으로 출력된다.

아그리고 setError가 좋은게
에러가 출력된 input으로 마우스를 자동포커싱해준다!!


만약 비밀번호 불일치 에러가 났을 때 마우스를 password1 input으로 강제포커싱 하고싶다면,
저 위 코드 message 객체 뒤에 shouldFocus: true 해주면 된다.


custom validation

만약 username에 "초연"이 포함되어있다면, 에러를 발생시켜보자.

이것을 위해 register에 validate를 추가해준다.
이 함수는 인자로 항목에 현재 쓰여지고 있는 값을 받는다.

  <input 
  {...register("username", {
    required: "write here", 
    minLength: 2,
    validate: (value)=>!value.includes("초연"),
  })} 
  placeholder="Username"
  />

이렇게 해주자.
이러면 value에 "초연"이 포함되지 않는다면 true를 반환한다.


위 두 사진에서 알 수 있듯이 username(4번째 input)에 "초연"이 포함되면 validate에 에러가 난다. Good

	validate: (value)=>
    	value.includes("초연") ? "no 초연 allowed" : true,


이렇게 해주면 만약 유저가 username에 "초연"을 포함해 작성한 경우 유저에게 "no 초연 allowed" 메세지를 보여주고 "초연"이 포함되지않은 경우엔 그대로 submit된다.

  validate:{
    noChoyeon:(value)=>
    value.includes("초연") ? "no 초연 allowed" : true,
      noNick: (value)=>
      value.includes("nick") ? "no nick allowed" : true, 
  },

이러면 이제 "초연"과 "nick" 모두 제한된다.

이렇게 우리가 원하는대로 validation해줄 수 있다.

setValue

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

interface IForm {
    toDo: string;
};

function ToDoList(){
    const { register, handleSubmit, setValue } = useForm<IForm>();
    const handleValid = (data: IForm) => {
      console.log("add to do", data.toDo);
      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;

이제 모든걸 지우고 여기서 다시 투두리스트 만들기를 시작한다.

setValue로 빈 문자열을 설정해주면 조건이 통과되어 submit되었을 때 input안을 비워준다.

profile
프론트로 멋쟁이되기 대장정,,

0개의 댓글