๐Ÿ“ React ๋ฆฌ์•กํŠธ ํšŒ์›๊ฐ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (Javascript) + ๋ฒ„ํŠผ ํƒœ๊ทธ disabled์ด๋ž€?

leememberยท2021๋…„ 10์›” 17์ผ
13
post-thumbnail

๐Ÿ“ TS ๊ธฐ๋ฐ˜์œผ๋กœ ์ง„ํ–‰์ค‘์ธ ํ”„๋กœ์ ํŠธ์—์„œ ๋‚ด๊ฐ€ ๋งก๊ฒŒ ๋œ ํšŒ์›๊ฐ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋ก
Formik๋‚˜ yup ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋„์›€ ์—†์ด ์ž‘์—…ํ–ˆ๋‹ค.

๐Ÿ‘‰ ๊ฒฐ๊ณผ๋ฌผ๋ถ€ํ„ฐ ๋ฐ”๋กœ๋ณด๊ธฐ

๐Ÿ‘‰ ์ „์ฒด์ฝ”๋“œ

๋ฒจ๋กœ๊ทธ ์ ‘๋Š”๊ธฐ๋Šฅ ์—†๋‚˜..


const SingUp = () => {
  //์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
  const [name, setName] = useState<string>('')
  const [email, setEmail] = useState<string>('')
  const [password, setPassword] = useState<string>('')
  const [passwordConfirm, setPasswordConfirm] = useState<string>('')

  //์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ ์ƒํƒœ์ €์žฅ
  const [nameMessage, setNameMessage] = useState<string>('')
  const [emailMessage, setEmailMessage] = useState<string>('')
  const [passwordMessage, setPasswordMessage] = useState<string>('')
  const [passwordConfirmMessage, setPasswordConfirmMessage] = useState<string>('')

  // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
  const [isName, setIsName] = useState<boolean>(false)
  const [isEmail, setIsEmail] = useState<boolean>(false)
  const [isPassword, setIsPassword] = useState<boolean>(false)
  const [isPasswordConfirm, setIsPasswordConfirm] = useState<boolean>(false)
  const router = useRouter()

  const onSubmit = useCallback(
    async (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault()
      try {
        await axios
          .post(REGISTER_USERS_URL, {
            username: name,
            password: password,
            email: email,
          })
          .then((res) => {
            console.log('response:', res)
            if (res.status === 200) {
              router.push('/sign_up/profile_start')
            }
          })
      } catch (err) {
        console.error(err)
      }
    },
    [email, name, password, router]
  )

  // ์ด๋ฆ„
  const onChangeName = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value)
    if (e.target.value.length < 2 || e.target.value.length > 5) {
      setNameMessage('2๊ธ€์ž ์ด์ƒ 5๊ธ€์ž ๋ฏธ๋งŒ์œผ๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.')
      setIsName(false)
    } else {
      setNameMessage('์˜ฌ๋ฐ”๋ฅธ ์ด๋ฆ„ ํ˜•์‹์ž…๋‹ˆ๋‹ค :)')
      setIsName(true)
    }
  }, [])

  // ์ด๋ฉ”์ผ
  const onChangeEmail = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const emailRegex =
      /([\w-.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
    const emailCurrent = e.target.value
    setEmail(emailCurrent)

    if (!emailRegex.test(emailCurrent)) {
      setEmailMessage('์ด๋ฉ”์ผ ํ˜•์‹์ด ํ‹€๋ ธ์–ด์š”! ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š” ใ…œ ใ…œ')
      setIsEmail(false)
    } else {
      setEmailMessage('์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹์ด์—์š” : )')
      setIsEmail(true)
    }
  }, [])

  // ๋น„๋ฐ€๋ฒˆํ˜ธ
  const onChangePassword = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,25}$/
    const passwordCurrent = e.target.value
    setPassword(passwordCurrent)

    if (!passwordRegex.test(passwordCurrent)) {
      setPasswordMessage('์ˆซ์ž+์˜๋ฌธ์ž+ํŠน์ˆ˜๋ฌธ์ž ์กฐํ•ฉ์œผ๋กœ 8์ž๋ฆฌ ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!')
      setIsPassword(false)
    } else {
      setPasswordMessage('์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ์—์š” : )')
      setIsPassword(true)
    }
  }, [])

  // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
  const onChangePasswordConfirm = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const passwordConfirmCurrent = e.target.value
      setPasswordConfirm(passwordConfirmCurrent)

      if (password === passwordConfirmCurrent) {
        setPasswordConfirmMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋˜‘๊ฐ™์ด ์ž…๋ ฅํ–ˆ์–ด์š” : )')
        setIsPasswordConfirm(true)
      } else {
        setPasswordConfirmMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ค์š”. ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š” ใ…œ ใ…œ')
        setIsPasswordConfirm(false)
      }
    },
    [password]
  )

  return (
    <>
      <Back />

      <Title title="ํšŒ์›๊ฐ€์ž…" className="loginMt" />

      <form css={selfWrap} onSubmit={onSubmit}>
        <div className="formbox">
          <TextField text="์ด๋ฆ„" type="text" typeName="name" onChange={onChangeName} />
          {name.length > 0 && <span className={`message ${isName ? 'success' : 'error'}`}>{nameMessage}</span>}
        </div>

        <div className="formbox">
          <TextField text="์ด๋ฉ”์ผ" type="email" typeName="email" onChange={onChangeEmail} />
          {email.length > 0 && <span className={`message ${isEmail ? 'success' : 'error'}`}>{emailMessage}</span>}
        </div>

        <div className="formbox">
          <PasswordField
            onChange={onChangePassword}
            passwordText="๋น„๋ฐ€๋ฒˆํ˜ธ (์ˆซ์ž+์˜๋ฌธ์ž+ํŠน์ˆ˜๋ฌธ์ž ์กฐํ•ฉ์œผ๋กœ 8์ž๋ฆฌ ์ด์ƒ)"
            title="๋น„๋ฐ€๋ฒˆํ˜ธ"
            typeTitle="password"
          />
          {password.length > 0 && (
            <span className={`message ${isPassword ? 'success' : 'error'}`}>{passwordMessage}</span>
          )}
        </div>

        <div className="formbox">
          <PasswordField
            onChange={onChangePasswordConfirm}
            passwordText=" "
            title="๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ"
            typeTitle="passwordConfirm"
          />
          {passwordConfirm.length > 0 && (
            <span className={`message ${isPasswordConfirm ? 'success' : 'error'}`}>{passwordConfirmMessage}</span>
          )}
        </div>

        {/* ์ด๋ฆ„, ์ด๋ฉ”์ผ, ํŒจ์Šค์›Œ๋“œ, ํŒจ์Šค์›Œ๋“œ ํ™•์ธ์ด ๋‹ค ๋งž๋‹ค๋ฉด ์ฃผํ™ฉ๋ฒ„ํŠผ์œผ๋กœ */}
        <div css={footButtonWrapper}>
          <section>
            <FootButton
              type="submit"
              footButtonType={FootButtonType.ACTIVATION}
              disabled={!(isName && isEmail && isPassword && isPasswordConfirm)}
            >
              ๋‹ค์Œ
            </FootButton>
          </section>
        </div>
      </form>
    </>
  )
}

export default SingUp

์ด ์ „์ฒด์ฝ”๋“œ๋“ค์„ ์„ธ๋ถ„ํ™”์‹œ์ผœ ๊ตฌ์กฐ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ‘‰ 1. View ๋‹จ ์ฝ”๋“œ

  • ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚ด๋Š” ๋ถ€๋ถ„๋ถ€ํ„ฐ ์„ค๋ช…
return (
    <>
      <Back />

      <Title title="ํšŒ์›๊ฐ€์ž…" className="loginMt" />

      <form css={selfWrap} onSubmit={onSubmit}>
        <div className="formbox">
          <TextField text="์ด๋ฆ„" type="text" typeName="name" onChange={onChangeName} />
          {name.length > 0 && <span className={`message ${isName ? 'success' : 'error'}`}>{nameMessage}</span>}
        </div>

        <div className="formbox">
          <TextField text="์ด๋ฉ”์ผ" type="email" typeName="email" onChange={onChangeEmail} />
          {email.length > 0 && <span className={`message ${isEmail ? 'success' : 'error'}`}>{emailMessage}</span>}
        </div>

        <div className="formbox">
          <PasswordField
            onChange={onChangePassword}
            passwordText="๋น„๋ฐ€๋ฒˆํ˜ธ (์ˆซ์ž+์˜๋ฌธ์ž+ํŠน์ˆ˜๋ฌธ์ž ์กฐํ•ฉ์œผ๋กœ 8์ž๋ฆฌ ์ด์ƒ)"
            title="๋น„๋ฐ€๋ฒˆํ˜ธ"
            typeTitle="password"
          />
          {password.length > 0 && (
            <span className={`message ${isPassword ? 'success' : 'error'}`}>{passwordMessage}</span>
          )}
        </div>

        <div className="formbox">
          <PasswordField
            onChange={onChangePasswordConfirm}
            passwordText=" "
            title="๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ"
            typeTitle="passwordConfirm"
          />
          {passwordConfirm.length > 0 && (
            <span className={`message ${isPasswordConfirm ? 'success' : 'error'}`}>{passwordConfirmMessage}</span>
          )}
        </div>

        {/* ์ด๋ฆ„, ์ด๋ฉ”์ผ, ํŒจ์Šค์›Œ๋“œ, ํŒจ์Šค์›Œ๋“œ ํ™•์ธ์ด ๋‹ค ๋งž๋‹ค๋ฉด ์ฃผํ™ฉ๋ฒ„ํŠผ์œผ๋กœ */}
        <div css={footButtonWrapper}>
          <section>
            <FootButton
              type="submit"
              footButtonType={FootButtonType.ACTIVATION}
              disabled={!(isName && isEmail && isPassword && isPasswordConfirm)}
            >
              ๋‹ค์Œ
            </FootButton>
          </section>
        </div>
      </form>
    </>
  )

view ๋‹จ์€ return() ์•ˆ์—๋‹ค๊ฐ€ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ํผํ˜•์‹์œผ๋กœ ๋งŒ๋“ค๊ณ  buttonํƒœ๊ทธ type์€ submit์œผ๋กœ ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ๋ฒ„ํŠผํƒœ๊ทธ ํƒ€์ž…์˜ default ๊ฐ’์€ submit์ด ๋งž๊ธดํ•˜๋‚˜. ๊ทธ๋ž˜๋„ ๊ตฌ์ฒด์ ์œผ๋กœ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด ๊ฐ ํผ ํ•„๋“œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๋ฅผ ๋ถ€์—ฌํ•ด์ค€๋‹ค. ์ €๋Š” input ๊ฐ’์— ๋‚ด์šฉ๋ฌผ๋“ค์ด ๋ฐ”๋€Œ๊ฒŒ ๋˜๋‹ˆ onChange์—๋‹ค๊ฐ€ ์ด๋ฒคํŠธ ํ•จ์ˆ˜๋ฅผ ๊ธฐ์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋„ค์ด๋ฐ ๊ทœ์น™์€ ๋ˆ„๊ตฌ๋‚˜ ์•Œ์•„๋ณด๊ธฐ ์‰ฝ๊ฒŒ ์ •ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ˆ ์ด๋ฆ„์—๋Š” onChangeName, ์ด๋ฉ”์ผ์€ onChangeEmail, ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” onChangePassword, ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์€ onChangePasswordConfirm ์ด๋ ‡๊ฒŒ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ์–ด๊ธ‹๋‚˜๊ฒŒ ์ž‘์„ฑํ–ˆ์„ ์‹œ, ์—๋Ÿฌ ํ‘œ์‹œ์— ๋Œ€ํ•œ ์ฝ”๋“œ๋„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.


{name.length > 0 && <span className={`message ${isName ? 'success' : 'error'}`}>{nameMessage}</span>}

์ด๋ ‡๊ฒŒ className="formbox" ์•ˆ์— ์žˆ๋Š” input ๋ฐ‘์— ์ค„์€ ์กฐ๊ฑด๋ถ€ ์—ฐ์‚ฐ์ž - ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—๋Ÿฌ๋ฅผ ํ‘œ๊ธฐํ•ด์ค๋‹ˆ๋‹ค. name์˜ length๊ฐ€ 0๋ณด๋‹ค ํฌ๋ฉด ๋‚ด์šฉ๋ฌผ์„ ์ถœ๋ ฅํ•ด๋ผ. ๋ผ๊ณ  ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
className ์•ˆ์—์„œ๋„ ์กฐ๊ฑด์‹์„ ๋‹ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋งŒ์•ฝ ์„ฑ๊ณต์ด๋ผ๋ฉด success ํด๋ ˆ์Šค๋ฅผ ! ํ‹€๋ ธ๋‹ค๋ฉด error ํด๋ ˆ์Šค๋กœ ๋‚˜ํƒ€๋‚ด์ค๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด๋Ÿฐ ํด๋ ˆ์Šค์— ์Šคํƒ€์ผ ๊ฐ’๋งŒ ์ ์šฉํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

.formbox {
    position: relative;
    margin-bottom: 20px;
    .message {
      font-weight: 500;
      font-size: 1.6rem;
      line-height: 24px;
      letter-spacing: -1px;
      position: absolute;
      bottom: -10px;
      left: 0;
      ๐Ÿ‘‰ &.success {
        color: #8f8c8b;
      }
      ๐Ÿ‘‰ &.error {
        color: #ff2727;
      }
    }
  }

์Šคํƒ€์ผ์€ ์ด๋Ÿฐ์‹์œผ๋กœ &.ํด๋ž˜์Šค๋ช…์„ ๋ถ™ํ˜€ ๊ฐ ์ƒํƒœ๋งˆ๋‹ค ์Šคํƒ€์ผ์„ ์ƒ์„ฑํ•ด์คฌ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘‰ useState ์ดˆ๊ธฐ ์ƒํƒœ๊ฐ’ ์„ ์–ธ

  //์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
  const [name, setName] = useState<string>('')
  const [email, setEmail] = useState<string>('')
  const [password, setPassword] = useState<string>('')
  const [passwordConfirm, setPasswordConfirm] = useState<string>('')

  //์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ ์ƒํƒœ์ €์žฅ
  const [nameMessage, setNameMessage] = useState<string>('')
  const [emailMessage, setEmailMessage] = useState<string>('')
  const [passwordMessage, setPasswordMessage] = useState<string>('')
  const [passwordConfirmMessage, setPasswordConfirmMessage] = useState<string>('')

  // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
  const [isName, setIsName] = useState<boolean>(false)
  const [isEmail, setIsEmail] = useState<boolean>(false)
  const [isPassword, setIsPassword] = useState<boolean>(false)
  const [isPasswordConfirm, setIsPasswordConfirm] = useState<boolean>(false)

form ์˜ ์—ญํ• ๋งˆ๋‹ค (์ด๋ฆ„, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ) useState๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐ๊ฐ’ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์ด๋‹ˆ ์ œ๋„ˆ๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ž…๊ฐ’ ๋ช…์‹œํ•ด์ฃผ๊ธฐ.
๊ทธ๋ฆฌ๊ณ  ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€์™€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋Œ€ํ•ด์„œ๋„ ์ƒํƒœ๊ฐ’์„ ์ƒ์ˆ˜๋กœ ์„ ์–ธํ•ด์ค๋‹ˆ๋‹ค.

๐Ÿ‘‰ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

  • input ๋‚ด์šฉ๋ฌผ๋“ค์ด ๋ฐ”๋€Œ๊ฒŒ ๋  ๋•Œ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์กฐ๊ฑด์‹์— ๋”ฐ๋ผ ์ƒํƒœ์— ๋ณ€ํ™”๋ฅผ ์ค์‹œ๋‹ค.
    async/await ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์—ฌ axios๋กœ API ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
    ์ œ๋Œ€๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜๋ฉด ๋„คํŠธ์›Œํฌ ์‘๋‹ต๊ฐ’์ด 200์œผ๋กœ ๋œจ๊ฒŒ๋˜๋Š”๋ฐ ์ด์— ์ผ์น˜ํ•˜๋ฉด
    ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๋„๋ก ๋™์ž‘ ๊ตฌํ˜„. ๊ทธ๋ ‡์ง€ ๋ชปํ•˜๋‹ค๋ฉด ์˜ˆ์™ธ์ฒ˜๋ฆฌ error ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ.
    useCallback์„ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”, ๋ Œ๋”๋ง ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์“ฐ๋Š”๋ฐ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์ธ ๋ฐฐ์—ด ์•ˆ์— ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“์•˜๋˜ ํ•จ์ˆ˜๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๊ทธ ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ™Œ ๋ฒ„ํŠผ ํด๋ฆญ ํ–ˆ์„ ๋•Œ(onSubmit) ๋ฐœ์ƒ๋˜๋Š” ์ด๋ฒคํŠธ

 
  const onSubmit = useCallback(
    async (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault()
      try {
        await axios
          .post(REGISTER_USERS_URL, {
            username: name,
            password: password,
            email: email,
          })
          .then((res) => {
            console.log('response:', res)
            if (res.status === 200) {
              router.push('/sign_up/profile_start')
            }
          })
      } catch (err) {
        console.error(err)
      }
    },
    [email, name, password, router]
  )

๐Ÿ™Œ input์— value๊ฐ’๋“ค์ด ๋ณ€๊ฒฝ๋  ๋•Œ์˜ onChange ์ด๋ฒคํŠธ

  • ์ด๋ฒคํŠธ ์กฐ๊ฑด์€ ๋ฐ˜๋“œ์‹œ return ๋ฐ–์—๋‹ค๊ฐ€ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
// ๐Ÿ“์ด๋ฆ„
  const onChangeName = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value)
    if (e.target.value.length < 2 || e.target.value.length > 5) {
      setNameMessage('2๊ธ€์ž ์ด์ƒ 5๊ธ€์ž ๋ฏธ๋งŒ์œผ๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.')
      setIsName(false)
    } else {
      setNameMessage('์˜ฌ๋ฐ”๋ฅธ ์ด๋ฆ„ ํ˜•์‹์ž…๋‹ˆ๋‹ค :)')
      setIsName(true)
    }
  }, [])

  // ๐Ÿ“์ด๋ฉ”์ผ
  const onChangeEmail = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const emailRegex =
      /([\w-.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
    const emailCurrent = e.target.value
    setEmail(emailCurrent)

    if (!emailRegex.test(emailCurrent)) {
      setEmailMessage('์ด๋ฉ”์ผ ํ˜•์‹์ด ํ‹€๋ ธ์–ด์š”! ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š” ใ…œ ใ…œ')
      setIsEmail(false)
    } else {
      setEmailMessage('์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹์ด์—์š” : )')
      setIsEmail(true)
    }
  }, [])

  // ๐Ÿ“๋น„๋ฐ€๋ฒˆํ˜ธ
  const onChangePassword = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,25}$/
    const passwordCurrent = e.target.value
    setPassword(passwordCurrent)

    if (!passwordRegex.test(passwordCurrent)) {
      setPasswordMessage('์ˆซ์ž+์˜๋ฌธ์ž+ํŠน์ˆ˜๋ฌธ์ž ์กฐํ•ฉ์œผ๋กœ 8์ž๋ฆฌ ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!')
      setIsPassword(false)
    } else {
      setPasswordMessage('์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ์—์š” : )')
      setIsPassword(true)
    }
  }, [])

  // ๐Ÿ“๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ
  const onChangePasswordConfirm = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const passwordConfirmCurrent = e.target.value
      setPasswordConfirm(passwordConfirmCurrent)

      if (password === passwordConfirmCurrent) {
        setPasswordConfirmMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋˜‘๊ฐ™์ด ์ž…๋ ฅํ–ˆ์–ด์š” : )')
        setIsPasswordConfirm(true)
      } else {
        setPasswordConfirmMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ค์š”. ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š” ใ…œ ใ…œ')
        setIsPasswordConfirm(false)
      }
    },
    [password]
  )

์ด๋ฆ„์€ 2๊ธ€์ž ์ด์ƒ 5๊ธ€์ž ๋ฏธ๋งŒ์œผ๋กœ ์กฐ๊ฑด์‹์„ ๋‚˜ํƒ€๋ƒˆ๊ณ , ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ทธ๊ฑฐ์— ๋งž๋Š” ์ •๊ทœ์‹ ํ‘œํ˜„์„ ๋ณ€์ˆ˜์— ๋‹ด์•„ ์กฐ๊ฑด์‹์— ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ Button disabled๋ž€ ?

<button> ํƒœ๊ทธ์˜ disabled ์†์„ฑ์€ ํ•ด๋‹น ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋จ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. disabled ์†์„ฑ์ด ๋ช…์‹œ๋œ ๋ฒ„ํŠผ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค. disabled ์†์„ฑ์€ ๋ถˆ๋ฆฌ์–ธ(boolean) ์†์„ฑ์ž…๋‹ˆ๋‹ค.

 <FootButton
              type="submit"
              footButtonType={FootButtonType.ACTIVATION}
              disabled={!(isName && isEmail && isPassword && isPasswordConfirm)}
            >
              ๋‹ค์Œ
            </FootButton>

๊ทธ๋ž˜์„œ ์ด๊ฒƒ๋„ ์กฐ๊ฑด๋ถ€ ์—ฐ์‚ฐ์‹์„ ํ†ตํ•ด ๋ชจ๋“  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์„ฑ๋ฆฝ๋œ๋‹ค๋ฉด ๋ฒ„ํŠผ์ด ๊ทธ์ œ์„œ์•ผ ์ฃผํ™ฉ์ƒ‰์œผ๋กœ ๋ณด์—ฌ์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

profile
์•„๋Š‘ํ•œ ๋‡Œ๊ณต๊ฐ„ ๐Ÿง 

2๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2022๋…„ 2์›” 14์ผ

์ง„์งœ ๋งŽ์ด ๋ฐฐ์› ์Šต๋‹ˆ๋‹คใ…œใ…œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค:)

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2022๋…„ 5์›” 16์ผ

๊ฐ์‚ฌํ•ด์š”!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ