๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Frontend/TypeScript

[ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(TypeScript) ] Formik์œผ๋กœ input state ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ

by YWTechIT 2022. 5. 27.
728x90

๐Ÿ“ Formik์œผ๋กœ input state ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ

์ด์ „ ๊ธ€์—์„œ 2๊ฐœ ์ด์ƒ์˜ useState๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด input์„ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, input์ด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค useState๋กœ ์ƒ์„ฑํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๊ณ , ํƒ€์ž…์ด ์—ฌ๋Ÿฌ ๊ฐ€์ง€์ผ ๋•Œ ๋งค๋ฒˆ ๊ทธ์— ๋งž๋Š” handleChange๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ์€ ์ƒ๋‹นํžˆ ๋ฒˆ๊ฑฐ๋กญ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๋„ ์ด๋ฏธ ๊ฐ™์€ ์ƒ๊ฐ์„ ํ–ˆ๋Š”์ง€, ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. Formik๊ณผ React Hook Form ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ๋ฐ, ์˜ค๋Š˜์€ Formik์— ๋Œ€ํ•ด์„œ ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณด์ž. Formik์€ React์—์„œ Form์„ ๊ตฌํ˜„ํ•  ๋•Œ ๊ฐ€์žฅ ์„ฑ๊ฐ€์‹  ์„ธ ๊ฐ€์ง€๋ฅผ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

1. ์–‘์‹ ์ƒํƒœ ์•ˆํŒŽ์—์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
2. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฐ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€
3. ์–‘์‹ ์ œ์ถœ ์ฒ˜๋ฆฌ

์œ„์˜ ๋ชจ๋“  ๊ฒฝ์šฐ์˜ ์ฝ”๋“œ๋ฅผ ํ•œ ๊ณณ์— ๋ฐฐ์น˜ํ•จ์œผ๋กœ์จ ํ…Œ์ŠคํŠธ์™€ ๋ฆฌํŒฉํ„ฐ๋ง, ์ถ”๋ก ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ณต์‹๋ฌธ์„œ์—๋„ ๋‚˜์™€์žˆ๋‹ค. (By colocating all of the above in one place, Formik will keep things organized--making testing, refactoring, and reasoning about your forms a breeze.)

 

๊ฒฐ๋ก ์ ์œผ๋กœ ๋‚ด๊ฐ€ Formik์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ฐ€์žฅ ํŽธํ•˜๊ฒŒ ์ƒ๊ฐํ–ˆ๋˜ ์ ์€ ์ด์ „์—” useState ํƒ€์ž…์— ๋”ฐ๋ผ handleChange ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ์ƒ์„ฑํ•ด์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ์—ˆ๋Š”๋ฐ, Formik์—์„œ ์ œ๊ณตํ•˜๋Š” handleChange๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ถ”๊ฐ€๋กœ handleBlur, handleSubmit๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜๋„ ์ž์ฒด์ ์œผ๋กœ ์ œ๊ณตํ•˜๋‹ˆ ๋งค๋ฒˆ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ „์ฒด ์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“œ๋Š” ์ƒ๋‹นํ•œ ์ด์ ์ด ์žˆ์—ˆ๋‹ค. ๋˜ํ•œ ์œ ํšจ์„ฑ(Validation) ๊ฒ€์‚ฌ๋„ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, form ํ˜•์‹์„ ์ œ์ถœ ํ•  ๋•Œ ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•˜๋Š” input์ด๋‚˜, ๊ตฌ์ฒด์ ์ธ minLength, maxLength ๊ธ€์ž ์ˆ˜๋ฅผ ์ •ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์ •๊ทœ ํ‘œํ˜„์‹์œผ๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ(input ๊ฐ’์ด ์ด๋ฉ”์ผ ํ˜•์‹์ธ์ง€ ์•„๋‹Œ์ง€)๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ž…๋ ฅ์„ ์™„๋ฃŒํ•œ ํ›„์— ํ•„๋“œ์˜ ์˜ค๋ฅ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ฒŒ ๋„์™€์ฃผ๋Š” errors ๊ธฐ๋Šฅ, form์„ ๋งŒ์กŒ๋Š”์ง€ ํ™•์ธํ•˜๋Š” touched๊ธฐ๋Šฅ ๋“ฑ์ด ์žˆ๋‹ค.

728x90

์•ž์„œ Formik์—์„œ๋Š” ์œ ํšจ์„ฑ(Validation) ๊ฒ€์‚ฌ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ๋Š”๋ฐ, Yup ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์Šคํ‚ค๋งˆ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ณต์‹๋ฌธ์„œ์—๋„ ๋‚˜์™€์žˆ๋“ฏ์ด ์œ ํšจ์„ฑ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด Yup์„ ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค(Yup is 100% optional.) ํ•˜์ง€๋งŒ, Yup์„ ์‚ฌ์šฉํ•˜๋ฉด ์งง์€ ์ฝ”๋“œ๋กœ๋„ ์ •ํ™•ํ•˜๊ฒŒ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ์งง์€ ์ฝ”๋“œ๋Š” ๊ฐ€๋…์„ฑ์„ ์ฆ๊ฐ€์‹œ์ผœ์ฃผ๊ณ  ์ด๋Š” ํ˜‘์—… ์‹œ ์ƒ์‚ฐ์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์š”์†Œ๊ฐ€ ๋œ๋‹ค.

 

Formik์˜ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ Getting Started์—๋„ ๋‚˜์™€ ์žˆ์ง€๋งŒ, ๋‚ด๊ฐ€ ์ง์ ‘ ๋งˆ์ฃผํ–ˆ๋˜ ์ฝ”๋“œ์˜ ์ „/ํ›„ ์ƒํƒœ๋ฅผ ๋ณด๋ฉด์„œ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋ฌด๋ž˜๋„ ๊ธฐ์–ต์— ์˜ค๋ž˜ ๋‚จ์„๊ฒƒ ๊ฐ™์•„ ์ฝ”๋“œ๋ฅผ ์ผ๋ถ€ ์ˆ˜์ •ํ•˜์—ฌ ๊ฐ€์ ธ์™”๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ธ”๋Ÿญ์€ Formik ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์˜ ์ฝ”๋“œ์ด๋‹ค. ์•„๋งˆ React๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒ ์ต์ˆ™ํ•œ ์ฝ”๋“œ์ด์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค.

 

์ฝ”๋“œ๋ฅผ ๋Œ€๋žต์ ์œผ๋กœ ์„ค๋ช…ํ•˜์ž๋ฉด, userEmail๊ณผ userName ๋ชจ๋‘ string ํƒ€์ž…์ด๋ผ ํ•˜๋‚˜์˜ useState์— ๋ฌถ์–ด์„œ ์„ ์–ธํ–ˆ๊ณ , personalInfo, adInfo ๋ชจ๋‘ boolean ํƒ€์ž…์ด๋ผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•˜๋‚˜์˜ useState์— ์„ ์–ธํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  handleInput์€ string์ด ๋ณ€ํ•˜๋Š” ๊ฐ’์„ ์ถ”์ ํ•˜๋Š” ํ•จ์ˆ˜์ด๊ณ , handlePartTerms๋Š” boolean ํƒ€์ž…์ด ๋ณ€ํ•˜๋Š” ๊ฐ’์„ ์ถ”์ ํ•˜๋Š” ํ•จ์ˆ˜, handleTotalTerms๋Š” boolean ๊ฐ’์„ ํ•œ๋ฒˆ์— ๋ชจ๋‘ ๋ฐ”๊ฟ”์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ํฌ๊ฒŒ ๋ณด๋ฉด handlePartTerms์™€ handleTotalTerms์˜ ์„ฑ๊ฒฉ์ด ๊ฐ™์•„ ๋ฌถ์–ด์„œ ์„ ์–ธํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ํผ์˜ ํ•„๋“œ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ๊ณผ ๋” ์œ„์ชฝ ๋ ˆ์ด์–ด์—์„œ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์ฐจ์ด๋ผ๋Š” ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋‚˜๋ˆ„๋Š” ํŽธ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋”ฐ๋กœ ์ •์˜ํ–ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ handleSubmit์€ form์—์„œ ์ œ์ถœ ํ•  ๋•Œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ง€๊ธˆ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ณด๋‹ค ๋”์šฑ ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด๊ถ๋ฌด์ง„ํ•˜์ง€๋งŒ, ํ˜„์žฌ ์ƒํƒœ์—์„œ๋Š” ํ•ธ๋“ค๋Ÿฌ ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“ ๋‹ค.

export default function WithoutFormik() {
  const [{ userEmail, userName }, setInput] = useState<InputType>({
    userEmail: '',
    userName: '',
  })
  const [{ personalInfo, adInfo }, setAgree] = useState<AgreeType>({
    personalInfo: false,
    adInfo: false,
  })

  const handleInput = (e: SyntheticEvent) => {
    const { id, value } = e.target as HTMLInputElement
    setInput((prevState) => ({ ...prevState, [id]: value }))
  }

  const handlePartTerms = (e: { target: HTMLInputElement }) => {
    const { id } = e.target

    setAgree((prevState) => ({
      ...prevState,
      [id]: !prevState[id],
    }))
  }

  const handleTotalTerms = (e: { target: HTMLInputElement }) => {
    const { checked } = e.target

    setAgree(
      checked
        ? {
            personalInfo: true,
            adInfo: true,
          }
        : {
            personalInfo: false,
            adInfo: false,
          },
    )
  }

  const handleSubmit = async () => {
    await applyServer({
      userEmail,
      userName,
      personalInfo,
      adInfo
    })
  }

  return(
    <>
      <Template />
    </>
  )
}

๊ทธ๋ ‡๋‹ค๋ฉด, Formik ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋Š” ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ–ˆ๋Š”์ง€ ์‚ดํŽด๋ณด์ž. ํ•˜๋‹จ ์ฝ”๋“œ ๋ธ”๋ก์„ ๋ณด๋ฉด ํ•œ๋ˆˆ์— ๋ด๋„ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ์ค„์–ด๋“  ๊ฒƒ์ด ๋ณด์ด์ง€ ์•Š๋Š”๊ฐ€? ๋˜ํ•œ, ๊ตฐ๋ฐ๊ตฐ๋ฐ ํฉ์–ด์ ธ ์žˆ๋˜ ์ฝ”๋“œ๊ฐ€ ํ•œ ๊ณณ์— ๋ชจ์—ฌ ์„ ์–ธ๋˜์–ด์žˆ์œผ๋‹ˆ ๊ฐ€๋…์„ฑ๋„ ๋งŽ์ด ์ข‹์•„์กŒ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด์ „ ์ฝ”๋“œ์—์„œ๋Š” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ฝ”๋“œ๋ฅผ ๋„ฃ์ง€ ์•Š์•˜๋Š”๋ฐ, ์—ฌ๊ธฐ์„  validationSchema๋ผ๋Š” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ฝ”๋“œ๊นŒ์ง€ ๊ฐ™์ด ๋„ฃ์—ˆ๋‹ค.(Yup ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.)

 

Formik์˜ ์žฅ์ ์€ handleChange ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํƒ€์ž…๋ณ„(string, boolean)๋กœ ๋”ฐ๋กœ ์ •์˜ํ•˜์ง€ ์•Š์•„๋„ handleChange ํ•˜๋‚˜๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ๊ณผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ isValid๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ๋ชจ๋‘ ํ†ต๊ณผํ•˜์ง€ ์•Š์œผ๋ฉด(์ด๋•Œ๋Š” isValid๊ฐ€ false๊ฐ€ ๋œ๋‹ค.) button์„ disabled๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ถ”๊ฐ€๋กœ input์˜ ์ตœ์†Œ / ์ตœ๋Œ€ ๊ธธ์ด๊นŒ์ง€ ์„ ์–ธํ•˜์—ฌ ํ•ด๋‹น ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋„ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  errors ๊ฐ์ฒด๋กœ validationSchema์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ํ†ต๊ณผํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ form์„ ์ œ์ถœํ•˜๊ณ  ์‘๋‹ต์ด ์˜ค๊ธฐ ์ „๊นŒ์ง€ button์„ disabled๋กœ ๋งŒ๋“œ๋Š” isSubmitting๊นŒ์ง€ ๋ณ„๋„์˜ ๋กœ์ง ์„ ์–ธ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ด ๋งˆ์Œ์— ๋“ค์—ˆ๋‹ค.

export default function WithFormik() {
  const {
    values,
    errors,
    isValid,
    isSubmitting,
    setValues,
    handleChange,
    handleSubmit,
  } = useFormik({
    initialValues: {
      userEmail: '',
      userName: '',
      personalInfo: false,
      adInfo: false,
    },
    validationSchema: Yup.object({
      userEmail: Yup.string()
        .email('์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.')
        .required('์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.'),
      userName: Yup.string().required('๋‹‰๋„ค์ž„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.'),
      personalInfo: Yup.bool().isTrue('๊ฐœ์ธ์ •๋ณด ์ˆ˜์ง‘์— ๋™์˜ํ•ด์ฃผ์„ธ์š”.'),
      adInfo: Yup.bool().isTrue('๊ด‘๊ณ ์„ฑ ์ •๋ณด ์ˆ˜์‹ ์— ๋™์˜ํ•ด์ฃผ์„ธ์š”.'),
    }),
    onSubmit: async ({email, nickname, personalInfo, adInfo}) => {
      await applyServer({
        email,
        nickname,
        personalInfo,
        adInfo,
      })
    },
  })

  const { userEmail, userName, personalInfo, adInfo } = values
  const isActive = isValid && !isSubmitting

  const allTermsHandleChange = () => {
    void setValues(
      checkedAllTerms
        ? {
            userEmail,
            userName,
            personalInfo: false,
            adInfo: false,
          }
        : {
            userEmail,
            userName,
            personalInfo: true,
            adInfo: true,
          },
    )
  }

  return(
    <>
      <Template />
    </>
  )
}

์ด๋ฐ–์—๋„ React Context์™€ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ useFormikContext, formํƒœ๊ทธ์— handleSubmit์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” <Form />, input ํƒœ๊ทธ์— handleChange๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” <Field />ํƒœ๊ทธ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜, Formik์—๋„ ๋‹จ์ ์€ ์กด์žฌํ•œ๋‹ค. ์ •ํ•ด์ง„ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ , ๋ณต์žกํ•œ form์„ ๋‹ค๋ฃจ๊ธฐ๊ฐ€ ์–ด๋ ต๊ณ  ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ปค์Šคํ…€ํ•˜๊ธฐ๊ฐ€ ์ผ๋ฐ˜์ ์ธ form์— ๋น„ํ•ด ์กฐ๊ธˆ์€ ๋ถˆํŽธํ•˜๋‹ค๋Š” ์ . ๊ทธ๋Ÿฌ๋‚˜, ์ด๋Ÿฐ ๋‹จ์ ์„ ๊ทน๋ณตํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ (input ๋กœ์ง์„ ์ผ์ผ์ด ๊ตฌํ˜„ํ•˜๊ธฐ ๊ท€์ฐฎ๊ฑฐ๋‚˜ ํ˜‘์—…ํ•  ๋•Œ ๋“ฑ)์ด ๋” ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ์ฏค Formik์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒํ•˜๋ฉฐ ์ด ๊ธ€์„ ๋งˆ์นœ๋‹ค.

 

Reference

  1. https://formik.org/docs/overview
  2. https://github.com/jquense/yup
  3. https://formik.org/docs/overview#the-gist
  4. https://formik.org/docs/migrating-v2#isvalid
  5. https://formik.org/docs/api/form
  6. https://formik.org/docs/api/field
  7. https://react-hook-form.com/
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€