๐ 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
์ด ์ ์ฒด์ฝ๋๋ค์ ์ธ๋ถํ์์ผ ๊ตฌ์กฐ์ ๋ํด ์ค๋ช ํด๋ณด๊ฒ ์ต๋๋ค.
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;
}
}
}
์คํ์ผ์ ์ด๋ฐ์์ผ๋ก &.ํด๋์ค๋ช ์ ๋ถํ ๊ฐ ์ํ๋ง๋ค ์คํ์ผ์ ์์ฑํด์คฌ์ต๋๋ค.
//์ด๋ฆ, ์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ, ๋น๋ฐ๋ฒํธ ํ์ธ
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๋ฅผ ์ฌ์ฉํ์ฌ ์ด๊ธฐ๊ฐ ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค. ํ์ ์คํฌ๋ฆฝํธ์ด๋ ์ ๋๋ฆญ์ ์ฌ์ฉํ์ฌ ํ์ ๊ฐ ๋ช ์ํด์ฃผ๊ธฐ.
๊ทธ๋ฆฌ๊ณ ์ค๋ฅ๋ฉ์์ง์ ์ ํจ์ฑ ๊ฒ์ฌ์ ๋ํด์๋ ์ํ๊ฐ์ ์์๋ก ์ ์ธํด์ค๋๋ค.
async/await
๋น๋๊ธฐ์ฒ๋ฆฌ๋ฅผ ํ์ฌ axios๋ก API ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์จ๋ค.
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]
)
์ด๋ฆ์ 2๊ธ์ ์ด์ 5๊ธ์ ๋ฏธ๋ง์ผ๋ก ์กฐ๊ฑด์์ ๋ํ๋๊ณ , ์ด๋ฉ์ผ๊ณผ ๋น๋ฐ๋ฒํธ๋ ๊ทธ๊ฑฐ์ ๋ง๋ ์ ๊ท์ ํํ์ ๋ณ์์ ๋ด์ ์กฐ๊ฑด์์ ํ์ฉํ์ต๋๋ค.
<button>
ํ๊ทธ์ disabled ์์ฑ์ ํด๋น ๋ฒํผ์ด ๋นํ์ฑํ๋จ์ ๋ช ์ํฉ๋๋ค. disabled ์์ฑ์ด ๋ช ์๋ ๋ฒํผ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ฌ์ฉ์๊ฐ ํด๋ฆญํ ์๋ ์์ต๋๋ค. disabled ์์ฑ์ ๋ถ๋ฆฌ์ธ(boolean) ์์ฑ์ ๋๋ค.
<FootButton
type="submit"
footButtonType={FootButtonType.ACTIVATION}
disabled={!(isName && isEmail && isPassword && isPasswordConfirm)}
>
๋ค์
</FootButton>
๊ทธ๋์ ์ด๊ฒ๋ ์กฐ๊ฑด๋ถ ์ฐ์ฐ์์ ํตํด ๋ชจ๋ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ์ฑ๋ฆฝ๋๋ค๋ฉด ๋ฒํผ์ด ๊ทธ์ ์์ผ ์ฃผํฉ์์ผ๋ก ๋ณด์ฌ์ง ์ ์๋๋ก ํ๋ค.
๊ฐ์ฌํฉ๋๋ค. ํ๋ก ํธ์๋ ๊ณต๋ถ์ค์ธ๋ฐ ๋ค๋ฅธ ๋ถ์ ์ฝ๋๋ฅผ ์จ๋ณด๋ ๊ฑด ์ฒ์์ธ๋ฐ์.. ํน์ ๊ด์ฐฎ์ผ์๋ค๋ฉด state์ ์ ํจ์ฑ๊ฒ์ฌ ๋ถ๋ถ ์ ์ฝ๋์ ์จ๋ ๋ ๊น์?
์ง์ง ๋ง์ด ๋ฐฐ์ ์ต๋๋คใ ใ ๊ฐ์ฌํฉ๋๋ค:)