🏠 | React-Hook-Form (Form Library)

NewHaΒ·2024λ…„ 2μ›” 11일
post-thumbnail

🌱 React Hook Form

Reactλ₯Ό μ‚¬μš©ν•΄ κ°œλ°œμ„ ν•˜λ‹€λ³΄λ©΄ λ‹€μ–‘ν•œ input μš”μ†Œλ₯Ό μ‚¬μš©ν•΄ form을 λ‹€λ£¨κ²Œ λ©λ‹ˆλ‹€.
이 λ•Œ Reactμ—μ„œ form을 λ‹€λ£¨λŠ” 전톡적인 방식은 λͺ‡ κ°€μ§€ λ¬Έμ œμ μ„ κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€.

πŸ‘Ύ Reactμ—μ„œ form을 λ‹€λ£¨λŠ” 전톡적인 방식(문제점)

  • Reactμ—μ„œλŠ” μƒνƒœ(State)λ₯Ό μ΄μš©ν•΄ μ‚¬μš©μžκ°€ μž…λ ₯ν•˜λŠ” 값을 κ΄€λ¦¬ν•˜λŠ” 방식을 μ‚¬μš©ν•©λ‹ˆλ‹€. μž…λ ₯κ°’κ³Ό react μƒνƒœκ°€ 항상 λ™κΈ°ν™”λ˜λ„λ‘ 보μž₯ν•˜μ§€λ§Œ, μ‚¬μš©μžκ°€ μž…λ ₯ν•  λ•Œλ§ˆλ‹€ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜κ³  μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¦¬λ Œλ”λ§ν•©λ‹ˆλ‹€. form에 input ν•„λ“œκ°€ λ§Žκ±°λ‚˜ λΉˆλ²ˆν•œ μƒνƒœ μ—…λ°μ΄νŠΈκ°€ μΌμ–΄λ‚˜λ©΄ μ„±λŠ₯ μ €ν•˜λ₯Ό μœ λ°œν•©λ‹ˆλ‹€.
  • λͺ¨λ“  form ν•„λ“œμ˜ μƒνƒœλ₯Ό μˆ˜λ™μœΌλ‘œ 관리해야 ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μƒνƒœλ₯Ό κ΄€λ¦¬ν•˜λŠ” 둜직이 λ³΅μž‘ν•΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. 특히, 동적인 form ν•„λ“œλ₯Ό λ‹€λ£° λ•Œ μ½”λ“œμ˜ λ³΅μž‘μ„±μ΄ 맀우 μ¦κ°€ν•©λ‹ˆλ‹€.
  • 각 input ν•„λ“œλ§ˆλ‹€ onChange ν•Έλ“€λŸ¬λ₯Ό μ„€μ •ν•˜κ³ , ν•Έλ“€λŸ¬ λ‚΄μ—μ„œ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” λ‘œμ§μ„ 반볡적으둜 μž‘μ„±ν•˜κ²Œ λ˜λ©΄μ„œ μ½”λ“œμ˜ 쀑볡이 λ°œμƒν•©λ‹ˆλ‹€. form이 컀질 수둝 더 λ§Žμ€ μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • form의 각 input ν•„λ“œμ˜ μœ νš¨μ„± 검사 λ‘œμ§μ„ 직접 μ„€μ •ν•˜κ³ , μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό κ΄€λ¦¬ν•˜λŠ” λ‘œμ§μ„ μΆ”κ°€μ μœΌλ‘œ μž‘μ„±ν•΄μ•Ό ν•©λ‹ˆλ‹€. λ³΅μž‘ν•œ formμ—μ„œλŠ” 둜직이 μƒλ‹Ήνžˆ λ³΅μž‘ν•΄μ§€κ³  μ½”λ“œμ˜ 가독성과 μœ μ§€λ³΄μˆ˜μ„±μ„ μ €ν•΄ν•©λ‹ˆλ‹€.
  • form을 제좜(submit)ν•  λ•Œ, 각 input의 μƒνƒœλ₯Ό λͺ¨μ•„μ„œ μ²˜λ¦¬ν•΄μ•Όν•˜κ³ , μœ νš¨μ„± 검사λ₯Ό μˆ˜ν–‰ν•œ 후에야 submit λ‘œμ§μ„ μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μœ νš¨μ„± 검사λ₯Ό ν†΅κ³Όν•˜μ§€ λͺ»ν•œ 경우의 λ‘œμ§κΉŒμ§€ κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.

πŸ’§ 전톡적 form μ˜ˆμ‹œ

import { useState } from 'react';
function Form() {
  // πŸ‘‰πŸ» λͺ¨λ“  ν•„λ“œμ˜ μƒνƒœλ₯Ό useState둜 μ„ μ–Έν•΄μ•Ό ν•œλ‹€.
  const [ email, setEmail ] = useState('');
  const [ password, setPassword ] = useState('');
  const [ errors, setErrors ] = useState({});
  const validateForm = () => {
  	let valid = true;
    let errors = {};
    // πŸ‘‰πŸ» 각 ν•„λ“œμ˜ μœ νš¨μ„± 검사 및 이벀트 ν•Έλ“€λŸ¬λ₯Ό ν•˜λ‚˜ ν•˜λ‚˜ λ‘œμ§μ„ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.
    if(!email) {
      errors.email = '이메일은 ν•„μˆ˜λ‘œ μž…λ ₯ν•˜λŠ” μš”μ†Œμž…λ‹ˆλ‹€.';
      valid = false;
    }
    //...
    return valid;
  }
  //...
  return (
    <form onSubmit={handleSubmit}>
      <input
        name='email'
        value='email'
        onChange={(e) => setEmail(e.target.value)}
      />
      {errors.email && <p>{errors.email}</p>}
      ...
    </form>
  );
}

μ΄λŸ¬ν•œ λ¬Έμ œλ“€μ„ ν•΄κ²°ν•˜κ³  form을 더 μ‰½κ²Œ 관리할 수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” λΌμ΄λΈŒλŸ¬λ¦¬κ°€ React-Hook-Formμž…λ‹ˆλ‹€. React Hooksλ₯Ό 기반으둜 μ„±λŠ₯ μ΅œμ ν™”μ™€ 개발 νŽΈμ˜μ„±μ„ λͺ¨λ‘ κ³ λ €ν•΄ μ„€κ³„λœ 라이브러리둜 2024λ…„ κΈ°μ€€μœΌλ‘œ React μƒνƒœκ³„μ—μ„œ 인기λ₯Ό μ–»κ³  μžˆμŠ΅λ‹ˆλ‹€.

React-Hook-Form을 μ‚¬μš©ν•˜λ©΄ λΆˆν•„μš”ν•œ μ—…λ°μ΄νŠΈμ™€ λ¦¬λ Œλ”λ§μ„ μ΅œμ†Œν™”ν•˜κ³  μƒνƒœκ΄€λ¦¬μ™€ μœ νš¨μ„± 검사 λ‘œμ§μ„ 더 κ°„κ²°ν•˜κ³  효율적으둜 μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ§€μ›ν•˜μ—¬ form의 νƒ€μž… μ•ˆμ •μ„±μ„ 보μž₯ν•©λ‹ˆλ‹€. μ΄λŠ” κ°œλ°œμ‹œ 였λ₯˜λ₯Ό 쀄이고 μ½”λ“œ ν’ˆμ§ˆμ„ ν–₯μƒμ‹œν‚΅λ‹ˆλ‹€.


β˜€οΈ μ„€μΉ˜ν•˜κΈ°

$ npm i react-hook-form
# ν˜Ήμ€
$ yarn add react-hook-form

ν„°λ―Έλ„μ΄λ‚˜ μ»€λ§¨λ“œλΌμΈμ„ 톡해 ν”„λ‘œμ νŠΈμ— 라이브러리λ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.

β˜€οΈ νŠΉμ§•

🌿 1. λΉ„μ œμ–΄ μ»΄ν¬λ„ŒνŠΈ (Uncontrolled Components)

React의 μƒνƒœ(State)λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , DOM 자체λ₯Ό 톡해 직접적이고 μžλ™μ μœΌλ‘œ μž…λ ₯ 값을 μ €μž₯ν•˜κ³  κ΄€λ¦¬ν•˜λŠ” 것을 λΉ„μ œμ–΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‚¬μš©ν•΄ μƒνƒœλ₯Ό κ΄€λ¦¬ν•œλ‹€κ³  ν•©λ‹ˆλ‹€. (일반적으둜 ReactλŠ” μ œμ–΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.)

즉, μ‚¬μš©μžκ°€ 값을 μž…λ ₯ν•˜λ©΄ μž…λ ₯된 λ°μ΄ν„°λŠ” μžλ™μœΌλ‘œ input, select, textareaλ“± μš”μ†Œμ˜ ν˜„μž¬κ°’μœΌλ‘œ μ„€μ •λ˜μ–΄ λΈŒλΌμš°μ € 내뢀에 μ €μž₯λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ™μž‘μ΄ Reactλ‚˜ JS라이브러리/ν”„λ ˆμž„μ›Œν¬ 없이 순수HTMLκ³Ό λΈŒλΌμš°μ €λ§ŒμœΌλ‘œ λ™μž‘ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ›Ή λΈŒλΌμš°μ €μ˜ ν™˜κ²½μ—μ„œ μ‚¬μš©λ˜κ³ , SSRμ΄λ‚˜ λ„€μ΄ν‹°λΈŒ μ•± λ“±μ˜ λ‹€λ₯Έ ν™˜κ²½μ—μ„œλŠ” μ§μ ‘μ μœΌλ‘œ μ μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈλ‚˜ React μƒνƒœ 관리 μ‹œμŠ€ν…œμ„ μš°νšŒν•˜μ—¬ μ–Έμ œλ“ μ§€ DOM으둜 직접 값을 μ‘°νšŒν•  수 μžˆμ–΄, μž…λ ₯μ‹œλ§ˆλ‹€ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜κ±°λ‚˜ λ¦¬λ Œλ”λ§ ν•˜μ§€ μ•Šμ•„ λΆˆν•„μš”ν•œ λ¦¬λ Œλ”λ§μ„ 쀄여 μ„±λŠ₯을 ν–₯μƒμ‹œν‚΅λ‹ˆλ‹€. 또, μƒνƒœλ₯Ό 직접 κ΄€λ¦¬ν•˜μ§€ μ•Šμ•„λ„ λ˜μ–΄ μ½”λ“œκ°€ κ°„κ²°ν•΄μ§€κ³  처리 둜직이 λ‹¨μˆœν•΄μ§‘λ‹ˆλ‹€.

🌿 2. Form data 관리(useForm)

μƒνƒœκ΄€λ¦¬, submit, μž…λ ₯κ°’ κ°μ‹œ, μ—λŸ¬λ©”μ‹œμ§€ 처리 λ“±μ˜ λ‹€μ–‘ν•œ μž‘μ—…μ„ useForm() 훅을 톡해 κ°„κ²°ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆμ–΄ 효율적으둜 κ΅¬ν˜„ν•˜κ³  데이터λ₯Ό 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ’§ React-Hook-Form Example

useForm 훅을 μ‚¬μš©ν•˜λ©΄ useState둜 μƒνƒœλ₯Ό 관리할 ν•„μš”κ°€ μ—†κ³ , onChangeν•Έλ“€λŸ¬λ₯Ό κ΅¬ν˜„ν•  ν•„μš”λ„ μ—†μŠ΅λ‹ˆλ‹€. μœ νš¨μ„± 검사 κ·œμΉ™μ„ μ‰½κ²Œ μ μš©ν•  수 있고, μ—λŸ¬λ©”μ‹œμ§€λ₯Ό μžλ™μœΌλ‘œ μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • λ‹€μŒμ€ useForm훅을 μ‚¬μš©ν•΄ λ§Œλ“  κ°„λ‹¨ν•œ form μ˜ˆμ‹œμž…λ‹ˆλ‹€. (vs. React 전톡적 form μ˜ˆμ‹œμ˜ μ½”λ“œ 와 비ꡐ해 많이 κ°„μ†Œμ‘ŒμŒμ— μ£Όλͺ©ν•΄μ£Όμ„Έμš”πŸ˜Ž)
// πŸ‘‰πŸ» μš°μ„  useForm 훅을 import ν•©λ‹ˆλ‹€.
import { useForm } from 'react-hook-form';
function Form() {
  // πŸ‘‰πŸ» useForm ν›…μ—μ„œ μ—¬λŸ¬ ν•¨μˆ˜λ₯Ό ꡬ쑰뢄해할당 ν•©λ‹ˆλ‹€.
  const { register, handleSubmit, watch, formState: {errors} } = useForm();
  // submit μ‹œ μ²˜λ¦¬ν•  λ™μž‘μ„ μ •ν•©λ‹ˆλ‹€. (handleSubmit() ν•¨μˆ˜μ— 인자둜 λ“€μ–΄κ°ˆ μ½œλ°±ν•¨μˆ˜)
  // onSubmit()은 μœ νš¨μ„± 검사λ₯Ό ν†΅κ³Όν•œ 경우 μ‹€ν–‰λ˜κ³ , onError()λŠ” μ‹€νŒ¨ν•œ 경우 싀행될 λ™μž‘μž…λ‹ˆλ‹€.
  const onSubmit = data => console.log(data);
  const onError = errors => console.error(errors);
  return (
    // πŸ‘‰πŸ» onSubmit event handler에 handleSubmit()ν•¨μˆ˜μ— onSubmit, onError μ½œλ°±ν•¨μˆ˜λ₯Ό λ„£μ–΄ λ“±λ‘ν•©λ‹ˆλ‹€.
    <form onSubmit={handleSubmit(onSubmit, onError)}>
      {/* πŸ‘‰πŸ» form field 등둝 : register() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄ 이름과 μœ νš¨μ„±κ²€μ‚¬λ₯Ό 전달 */}
      <input {...register('email', {required: 'email is required'}) } />
      {/* πŸ‘‰πŸ» form field의 μœ νš¨μ„± 검사 μ—λŸ¬κ°€ μžˆλ‹€λ©΄ 확인해 μ—λŸ¬λ©”μ‹œμ§€ ν‘œμ‹œν•˜λŠ” 쑰건뢀 λ Œλ”λ§ */}
      {errors.email && <p>{errors.email.message}</p>}
      <input {...register('password', {required: 'password is required'}) } />
      {errors.password && <p>{errors.password.message}</p>}
      <button type='submit'>제좜</button>
    </form>
  );
}
  • useForm()의 λͺ¨λ“  속성을 ν™•μΈν•˜λ €λ©΄ μ—¬κΈ°μ—μ„œ ν™•μΈν•˜μ„Έμš” πŸ˜€

🌳 form field 등둝

register()ν•¨μˆ˜λ₯Ό 톡해 form의 ν•„λ“œ(input, select λ“±)λ₯Ό React-Hook-Form에 λ“±λ‘ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 React-Hook-Form이 ν•΄λ‹Ή ν•„λ“œμ˜ κ°’ λ³€ν™”λ₯Ό κ°μ§€ν•˜κ³ , μœ νš¨μ„± 검사λ₯Ό μ‹€ν–‰ν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

// πŸ‘‰πŸ» useForm hookμ—μ„œ register ν•¨μˆ˜λ₯Ό κ°€μ Έμ˜¨λ‹€.
const { register } = useForm();

return (
  //πŸ‘‰πŸ» form λ‚΄μ—μ„œ μ‚¬μš©ν•˜λŠ” μž…λ ₯ ν•„λ“œλ₯Ό register ν•¨μˆ˜λ‘œ λ“±λ‘ν•œλ‹€.
	<input {...register('field_name', { required: true })} />
  );
  • 첫번째 인자둜 field_name을 적어 λ“±λ‘ν•˜κ³ , λ‘λ²ˆμ§Έ 인자둜 μœ νš¨μ„± 검사에 μ‚¬μš©ν•  κ·œμΉ™ 객체λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€.

🌳 Submit 처리

useForm()ν›…μ—μ„œλŠ” handleSubmit()ν•¨μˆ˜λ₯Ό μ œκ³΅ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” 제좜(submit) 이벀트 λ°œμƒμ‹œ formDataλ₯Ό 인자둜 λ°›μ•„ 싀행될 두 개의 μ½œλ°±ν•¨μˆ˜λ₯Ό λ°›μŠ΅λ‹ˆλ‹€. ν•˜λ‚˜λŠ” λ‚΄λΆ€μ μœΌλ‘œ μœ νš¨μ„± 검사λ₯Ό ν†΅κ³Όν•œ κ²½μš°μ— ν˜ΈμΆœν•  ν•¨μˆ˜(onSubmit)둜 μ‹€μ œ 데이터 처리 λ‘œμ§μ„ μˆ˜ν–‰ν•˜κ³ , ν•˜λ‚˜λŠ” μ‹€νŒ¨ν•  경우 ν˜ΈμΆœν•  ν•¨μˆ˜(onError)μž…λ‹ˆλ‹€.

 // πŸ‘‰πŸ» useForm ν›…μ—μ„œ handleSubmit ν•¨μˆ˜λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€.
  const { handleSubmit } = useForm();
  const onSubmit = data => console.log(data);
  const onError = errors => console.error(errors);

  return (
    // πŸ‘‰πŸ» onSubmit μ½œλ°±ν•¨μˆ˜λ₯Ό handleSubmitν•¨μˆ˜μ˜ 인자둜 λ„£μ–΄ onSubmit μ΄λ²€νŠΈμ— λ“±λ‘ν•©λ‹ˆλ‹€.
    <form onSubmit={handleSubmit(onSubmit, onError)}>
      {/*Form Field */}
    </form>
  )
}

🌳 μ—λŸ¬ λ©”μ‹œμ§€ ν‘œμ‹œ

errors κ°μ²΄λŠ” form ν•„λ“œμ˜ μœ νš¨μ„± 검사 μ—λŸ¬λ₯Ό μ €μž₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 훅을 톡해 각 ν•„λ“œμ— λŒ€ν•œ μ—λŸ¬λ₯Ό ν™•μΈν•˜κ³  쑰건뢀 λ Œλ”λ§μœΌλ‘œ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μ‚¬μš©μžμ—κ²Œ ν‘œμ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

//πŸ‘‰πŸ» μœ νš¨μ„± 검사 μ‹€νŒ¨μ˜ ꡬ체적인 이유λ₯Ό 담은 객체
const { errors } = useForm();
return (
  ...
  {errors.field_name && <p>{errors.field_name.message}</p>}
  ...
 );

🌳 μž…λ ₯ κ°’(data) κ°μ‹œ

watch() ν•¨μˆ˜λ₯Ό 톡해 νŠΉμ • μž…λ ₯λž€μ˜ κ°’μ΄λ‚˜, form μ „μ²΄μ˜ μž…λ ₯ κ°’μ˜ λ³€ν™”λ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ κ°μ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ°μ‹œν•˜κ³ μž ν•˜λŠ” ν•„λ“œ 이름을 인자둜 λ°›κ³ , ν•΄λ‹Ή ν•„λ“œμ˜ ν˜„μž¬ 값을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

watch()λ₯Ό 톡해 form의 νŠΉμ • 뢀뢄을 μ‘°κ±΄λΆ€λ‘œ λ Œλ”λ§ν•˜κ±°λ‚˜, μž…λ ₯ 값에 따라 좔가적인 λ‘œμ§μ„ μˆ˜ν–‰ν•΄μ•Ό ν•  λ•Œ μœ μš©ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

function Form() {
  const { watch } = useForm();
  const fieldValue = watch('field_name'); // πŸ‘‰πŸ» νŠΉμ • ν•„λ“œμ˜ 값을 κ°μ‹œν•΄ ν˜„μž¬ 값을 fieldValue에 μ €μž₯
  // πŸ‘‰πŸ» fieldValue 값을 μ‚¬μš©ν•΄ λ‹€μ–‘ν•œ 둜직 μˆ˜ν–‰ κ°€λŠ₯!
}

🌳 Options

  • mode : mode μ˜΅μ…˜μœΌλ‘œ μœ νš¨μ„± 검사가 싀행될 타이밍을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • onChange(default, ν•„λ“œ 값이 변경될 λ•Œλ§ˆλ‹€ μœ νš¨μ„±μ„ μž¬κ²€μ‚¬)
    • onBlur(포컀슀λ₯Ό μžƒμ—ˆμ„ λ•Œ μœ νš¨μ„± μž¬κ²€μ‚¬)
    • onSubmit(μ œμΆœμ‹œμ—λ§Œ μœ νš¨μ„±μ„ μž¬κ²€μ‚¬) 등이 μžˆμŠ΅λ‹ˆλ‹€.
const { register, handleSubtmi, watch, errors } = useForm({ mode: 'onSubmit' });
  • defaultValues : form ν•„λ“œκ°€ λ Œλ”λ§λ  λ•Œ 각 ν•„λ“œμ— 적용될 μ΄ˆκΈ°κ°’μ„ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
const { register, handleSubtmi, watch, errors } = useForm({ defaultValues: {name: 'newha'} });
  • reValidateMode : μœ νš¨μ„± κ²€μ‚¬μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•œ 경우, λ‹€μ‹œ 검사할 쑰건을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
const { register, handleSubtmi, watch, errors } = useForm({ reValidateMode: 'onSubmit' });
  • resolver : Yup, Joi, Superstruct 와같은 μ™ΈλΆ€ 검증 μŠ€ν‚€λ§ˆ λΌμ΄λΈŒλŸ¬λ¦¬μ™€μ˜ 톡합을 μ§€μ›ν•©λ‹ˆλ‹€. resolver ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³ , ν•¨μˆ˜ λ‚΄μ—μ„œ μ™ΈλΆ€ 라이브러리의 μœ νš¨μ„± 검사 λ‘œμ§μ„ μ‹€ν–‰ν•œ ν›„, κ²°κ³Όλ₯Ό λ°˜λ³΅ν•΄ λ³΅μž‘ν•œ 검증 λ‘œμ§μ„ 보닀 μ„ μ–Έμ μœΌλ‘œ 관톡합해 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. yupResolverκ³Ό 같은 resolverκ°€ μžˆμŠ΅λ‹ˆλ‹€.

🌿 3. Form Validation (폼 검증)

μ‚¬μš©μžκ°€ μž…λ ₯λž€μ— μ˜¬λ°”λ₯Έ 데이터λ₯Ό μΌλŠ”μ§€(μœ νš¨μ„± 검사) μ‰½κ²Œ 확인할 수 μžˆλŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.

ν•„μš”ν•œ data ν˜•μ‹κ³Ό μ‚¬μš©μžκ°€ μž…λ ₯ν•œ data ν˜•μ‹μ΄ 같은지 ν™•μΈν•˜μ—¬ λ°μ΄ν„°μ˜ 정확성을 보μž₯ν•˜κ³ , μ‚¬μš©μžμ—κ²Œ μœ νš¨ν•œ ν˜•μ‹μ„ μ•Œλ €μ£Όμ–΄ 더 λ‚˜μ€ μ‚¬μš©μž κ²½ν—˜μ„ μ œκ³΅ν•˜λŠ” 검사λ₯Ό μœ νš¨μ„± 검사라고 ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ '이메일 μ£Όμ†Œκ°€ μ˜¬λ°”λ₯Έ ν˜•μ‹μΈκ°€?', 'λΉ„λ°€λ²ˆν˜Έκ°€ μΆ©λΆ„νžˆ μ•ˆμ „ν•œκ°€?' 같은 μœ νš¨μ„±μ„ 쉽고 효과적으둜 검증할 수 μžˆμŠ΅λ‹ˆλ‹€.

🌳 κΈ°λ³Έ 검증 κ·œμΉ™

κ°„λ‹¨ν•œ 검증 κ·œμΉ™μ€ register() ν•¨μˆ˜μ— 객체 ν˜•νƒœλ‘œ μ „λ‹¬ν•˜μ—¬, νŠΉμ • μž…λ ₯λž€μ— λŒ€ν•œ 검증 λ‘œμ§μ„ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

// μ•žμœΌλ‘œ μ„€λͺ…μ—μ„œμ˜ μ˜ˆμ‹œ μ½”λ“œκ°€ {κ²€μ¦κ·œμΉ™} 뢀뢄에 λ“€μ–΄κ°€κ²Œ λ©λ‹ˆλ‹€.
<input ref={register({/* πŸ‘‰πŸ»κ²€μ¦ κ·œμΉ™!!!!!πŸ‘ˆπŸ» */})} />
  • required : ν•„μˆ˜λ‘œ μž…λ ₯λ˜μ–΄μ•Ό ν•˜λŠ” ν•„λ“œμž„μ„ λ‚˜νƒ€λ‚΄κ³ , μ‚¬μš©μžλŠ” ν•΄λ‹Ή ν•„λ“œλ₯Ό λΉ„μ›Œ μ œμΆœν•  수 μ—ˆμŠ΅λ‹ˆλ‹€. {required: true} ν˜Ήμ€ {required: 'ν•„μˆ˜λ‘œ μž…λ ₯ν•΄μ•Ό ν•©λ‹ˆλ‹€.'}와 같이 μ—λŸ¬λ©”μ‹œμ§€λ₯Ό 포함해 적을 수 μžˆμŠ΅λ‹ˆλ‹€.

  • minLength / maxLength : λ¬Έμžμ—΄μ΄λ‚˜ λ°°μ—΄μ˜ 길이에 μ μš©ν•΄ μž…λ ₯κ°’μ˜ μ΅œμ†Œ 길이와 μ΅œλŒ€ 길이λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. {minLength: 6}(μ΅œμ†Œ 6κΈ€μž 이상)κ³Ό 같이 적을 수 μžˆμŠ΅λ‹ˆλ‹€.

  • min / max : 숫자 μž…λ ₯ ν•„λ“œμ—μ„œ μ΅œμ†Œκ°’κ³Ό μ΅œλŒ€κ°’μ„ μ§€μ •ν•˜μ—¬ κ°’μ˜ λ²”μœ„λ₯Ό μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€. {min: 1, max: 5}(μ΅œμ†Œ 1이상, μ΅œλŒ€ 5μ΄ν•˜)와 같이 μ‚¬μ΄μ˜ μž…λ ₯값을 μš”κ΅¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • pattern : μž…λ ₯값이 νŠΉμ • νŒ¨ν„΄(μ •κ·œν‘œν˜„μ‹)κ³Ό μΌμΉ˜ν•˜λ„λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이메일 μ£Όμ†Œ, μ „ν™”λ²ˆν˜Έ λ“± 처럼 νŠΉμ • ν˜•μ‹μ„ κ°–μΆ˜ λ¬Έμžμ—΄μ„ 검사할 수 μžˆμŠ΅λ‹ˆλ‹€. {pattern: /^[A-Za-z]+$/}(μ•ŒνŒŒλ²³λ§Œ 인정)처럼 νŠΉμ • ν˜•μ‹μ„ μš”κ΅¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

🌳 쑰건뢀 검증 κ·œμΉ™

νŠΉμ • 쑰건에 따라 form fieldλ₯Ό λ‹€λ₯΄κ²Œ 검증해야 ν•  경우, μœ μ—°ν•˜κ²Œ μ‘°κ±΄λΆ€λ‘œ μ»€μŠ€ν…€ 검증 κ·œμΉ™μ„ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, λΉ„λ°€λ²ˆν˜Έ ν™•μΈλž€κ³Ό 같이 두 μž…λ ₯λž€μ˜ 값이 μΌμΉ˜ν•˜λŠ” μ§€ ν™•μΈν•˜λŠ” λ“±μ˜ μž‘μ—…μ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • validate : μž…λ ₯λž€μ˜ 이름을 ν‚€(Key)둜 ν•˜κ³ , κ·Έ κ°’μœΌλ‘œ ture/false둜 ν™•μΈλ˜λŠ” 검증 ν•¨μˆ˜λ₯Ό κ°€μ§‘λ‹ˆλ‹€. 검증 ν•¨μˆ˜λŠ” μž…λ ₯값을 λ°›μ•„ μœ νš¨μ„±μ„ κ²€μ‚¬ν•˜κ³ , μœ νš¨ν•˜μ§€ μ•Šμ„ 경우 returnκ°’μœΌλ‘œ λ¬Έμžμ—΄μ„ μ£Όλ©΄ 였λ₯˜ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
const { register, handleSubmit, watch, errors } = useForm({
  // μž…λ ₯λž€μ— λŒ€ν•œ μœ νš¨μ„± 검사λ₯Ό μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  validate: {
    confirmPassword: value => {
      const password = watch('password'); // πŸ‘‰πŸ» λΉ„λ°€λ²ˆν˜Έ μž…λ ₯λž€μ˜ 값을 κ°€μ Έμ˜€κΈ°
      if(value !== password) {
        return "λΉ„λ°€λ²ˆν˜Έμ™€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.";
      }
      return ture;  // πŸ‘‰πŸ» μœ νš¨μ„± 검사 톡과
    }
  }
});

β˜€οΈ ν”„λ‘œμ νŠΈ μ‚¬μš©λ‘€

  • νšŒμ›κ°€μž… νŽ˜μ΄μ§€μ—μ„œ μ‚¬μš©ν•œ μ˜ˆμ‹œμž…λ‹ˆλ‹€.
import { FormProvider, useForm, SubmitHandler } from 'react-hook-form'

export default function SignUpPage() {
  const Form = FormProvider;
  const form = useForm();
  
  const onSubmitSignUp = async (formData) => {
    // supabase에 κ°€μž…μš”μ²­ν•˜λŠ” ν•¨μˆ˜μ— μž…λ ₯받은 formDataλ₯Ό λ„˜κΈ°λŠ” onSubmit ν•¨μˆ˜
    await signUpEmail(formData); 
  };
  
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmitSignUp)}>
        <input type="text" 
          	   name="email" 
          	   options={{	// πŸ‘‰πŸ» options에 κ·œμΉ™"객체"λ₯Ό μ „λ‹¬ν•΄μ•Όν•©λ‹ˆλ‹€.
            	required: "ν•„μˆ˜ν•­λͺ©μž…λ‹ˆλ‹€.",  // πŸ‘‰πŸ» ν•„μˆ˜μž…λ ₯λž€μ΄λΌλŠ” 쑰건
                pattern: {  // πŸ‘‰πŸ» pattern으둜 이메일 ν˜•μ‹μ„ κ²€μ‚¬ν•˜λŠ” "μ •κ·œν‘œν˜„μ‹"κ³Ό μ—λŸ¬λ©”μ‹œμ§€λ₯Ό 전달
                  value: /^([a-z0-9_.-]+)@([\da-z.-]+)\.([a-z.]{2,6})$/,
                  message: "이메일 ν˜•μ‹μœΌλ‘œ μž…λ ₯ν•΄μ£Όμ„Έμš”.",
                },	
               }}
          	   placeholder="이메일 μ£Όμ†Œλ₯Ό μž…λ ₯ν•˜μ„Έμš”."
        />
        <span>{form.formState.errors[email]?.message}</span>  // πŸ‘‰πŸ» μ—λŸ¬κ°€ μžˆλ‹€λ©΄ λ©”μ‹œμ§€λ₯Ό 띄움
        <input type="password"
          	   name="password"
          	   options={{
            	required: "λΉ„λ°€λ²ˆν˜Έλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”.",
                minLength: {  // πŸ‘‰πŸ» μ΅œμ†Œ 길이 검증 & μ—λŸ¬λ©”μ‹œμ§€
                  value: 8,
                  message: "영문, 숫자, 특수기호λ₯Ό ν¬ν•¨ν•˜μ—¬ 8자리 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.",
                },
                pattern: {
                  value: /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,15}$/,
                  message:
                    '영문, 숫자, 특수기호λ₯Ό ν¬ν•¨ν•˜μ—¬ 8자리 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.',
                },
               }}
          	   placeholder="λΉ„λ°€λ²ˆν˜Έλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”"
        />
        <span>{form.formState.errors[password]?.message}</span>
        <input type="password"
          	   name="ConfirmPassword"
          	   options={{
            	required: "λΉ„λ°€λ²ˆν˜Έλ₯Ό ν™•μΈν•΄μ£Όμ„Έμš”.",
                validate: {	  // πŸ‘‰πŸ» validate둜 ν•¨μˆ˜λ‘œ μ—¬λŸ¬ 검증쑰건 μž‘μ„± κ°€λŠ₯(True/False νŒλ‹¨)
                  confirmPassword: (value) => {  // πŸ‘‰πŸ» λΉ„λ°€λ²ˆν˜Έλž€κ³Ό λΉ„λ°€λ²ˆν˜Έ ν™•μΈλž€μ˜ μž…λ ₯값이 같은 μ§€ ν™•μΈν•˜λŠ” ν•¨μˆ˜
                    const { password } = form.getValues();
                    return (  // πŸ‘‰πŸ» return 값이 λ¬Έμžμ—΄μ΄λ©΄ μ—λŸ¬λ©”μ‹œμ§€λ‘œ λ¦¬ν„΄ν•œλ‹€.
                      password === value || "λΉ„λ°€λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
                    );	
                  },
                },
               }}
          	   placeholder="λΉ„λ°€λ²ˆν˜Έλ₯Ό ν™•μΈν•΄μ£Όμ„Έμš”"
        />
        <span>{form.formState.errors[confirmPassword]?.message}</span>
      </form>
    </Form>
  );
}

πŸ‘€ Reference

profile
λ°± λ²ˆμ„ 보면 ν•œ κ°€μ§€λŠ” μ•ˆλ‹€ πŸ‘€

0개의 λŒ“κΈ€