์งํ ์ํฉ
login-email.tsx
- API ์ฐ๋
- ์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ
- ์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ ์ผ์น ์ฌ๋ถ ํ์ธ
- ๋ชจ๋ ํต๊ณผ ํ local Storage์ token ๊ฐ ์ ์ฅ ์ฌ๋ถ ํ์ธ
- ๊ฐ๋จํ๊ฒ ํผ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ ์ ์๋ ํผ ๊ฒ์ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
๐ธ ์ค์น
npm install react-hook-form
yarn add react-hook-form
useForm
์ ํผ์ ์ฝ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํ custom hook
type FormInputs = {
firstName: string;
lastName: string;
};
const { register } = useForm<FormInputs>({
mode: 'onSubmit',
reValidateMode: 'onChange',
defaultValues: {},
resolver: undefined,
context: undefined,
criteriaMode: "firstError",
shouldFocusError: true,
shouldUnregister: true,
})
const { register } = useForm<{ firstName: string; lastName: string; }>({
mode: 'onSubmit',
reValidateMode: 'onChange',
defaultValues: {},
resolver: undefined,
context: undefined,
criteriaMode: "firstError",
shouldFocusError: true,
shouldUnregister: true,
})
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
onSubmit
(default) : string | submit
์ด๋ฒคํธ๊ฐ ์ผ์ด๋ ๋ ์ ํจ์ฑ ๊ฒ์ฌ, ์ ํจํ์ง ์์ ์
๋ ฅ์ onChange
์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฐ๊ฒฐํ์ฌ ์ ํจ์ฑ์ ๋ค์ ํ์ธ
onChange
: string | input์ value๊ฐ ๋ณํ ๋๋ง๋ค ์ ํจ์ฑ ๊ฒ์ฌ, ์ฌ๋ฌ๋ฒ ๋ฆฌ๋๋๋ง (๋๋๋ง ์ฑ๋ฅ์ ๋จ์ด๋จ๋ฆฌ๋ฏ๋ก ์ถ์ฒํ์ง ์์ต๋๋ค.)
register: (name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref})
register
๋ฉ์๋๋ input์ด๋ select ์์์ ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น์ ์ค์ ํ ์ ์๋ค.
ref
: React.RefObject | React element ref
<input name="test" ref={register} />
required
: boolean | ํ์ ์์๋ฅผ ์ง์ ํ ๋, true
๋ก ์ง์
<input
name="test"
ref={
register({
required: true
})
}
/>
maxLength
, minLength
: number | ์
๋ ฅ์ ํ์ฉ๋๋ ์ต๋/์ต์ ๊ธธ์ด
<input
name="test"
ref={
register({
maxLength: 2
})
}
/>
pattern
: RegExp | ์ ๊ท์ ํจํด์ ์ด์ฉํ์ฌ ์ ํจ์ฑ ๊ฒ์ฌ ๊ฐ๋ฅ
<input
name="test"
ref={
register({
pattern: /[A-Za-z]{3}/
})
}
/>
handleSubmit: ((data: Object, e?: Event) => void, (errors: Object, e?: Event) => void) => Function
handleSubmit
ํจ์๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํต๊ณผํ์ ๋ ํผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋๋ค.
handleSubmit
ํจ์๋ฅผ ํตํด ๋น๋๊ธฐ๋ก ํผ์ submit
ํ ์ ์๋ค.
handleSubmit(onSubmit)();
handleSubmit(async (data) => await fetchAPI(data))
SubmitHandler
: (data: Object, e?: Event) => void | A successful callback
SubmitErrorHandler
: (errors: Object, e?: Event) => void | An error callback.
formState
๋ ๋ง ๊ทธ๋๋ก ํผ์ ์ํ์ ๋ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ค.
formState
is wrapped with a Proxy to improve render performance and skip extra logic if specific state is not subscribed to. Therefore make sure you invoke or read it before a render in order to enable the state update.
=> ์์ญํด์ ์์ฑํด๋ณด๋ ค๊ณ ํ์ผ๋ ์คํจ
import React from "react";
import { useForm } from "react-hook-form";
export default function App () {
const {
register,
handleSubmit,
formState
} = useForm();
const onSubmit = (data) => console.log(data);
React.useEffect(() => {
console.log("touchedFields", formState.touchedFields);
},[formState]);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("test")} />
<input type="submit" />
</form>
);
};
isValid
: boolean | ํผ์ ์๋ฌ๊ฐ ์์ ๊ฒฝ์ฐ true
isValid
๋ useForm
mode
๊ฐ onChange
, onTouched
, onBlur
์ผ ๊ฒฝ์ฐ์ ๋ง ์ ์ฉํ ์ ์๋ค.
errors
: object | ErrorMessage
์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํ๋ฉด ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฝ๊ฒ ๊ฒ์ํ ์ ์๋ค.
๐ธ ์ด๋ฉ์ผ๋ก ๋ก๊ทธ์ธํ๋ ํ์ด์ง ์ฝ๋
import { useForm } from 'react-hook-form';
const LoginEmail: NextPage = () => {
const router = useRouter();
useEffect(() => {
if (localStorage.getItem('token')) {
router.push('/');
}
}, []);
const regExpEm =
/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
const regExgPw = /^[A-Za-z0-9]{6,12}$/;
const [loginError, setLoginError] = useState<boolean>(false);
const {
register,
handleSubmit,
formState: { errors, isValid },
} = useForm<{ email: string; password: string }>({ mode: 'onChange' });
const onSubmit = handleSubmit(async (data) => {
const res = await axios(`${API_ENDPOINT}/user/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
user: {
email: data.email,
password: data.password,
},
}),
});
if (res.data.message) {
setLoginError(true);
} else {
localStorage.setItem('account', res.data.user.accountname);
localStorage.setItem('token', res.data.user.token);
router.push('/');
}
});
return (
<>
<Head>
<title>๋ก๊ทธ์ธใ
ฃ๋๊นกํ</title>
</Head>
<MainLoginEmail>
<TitleMain>๋ก๊ทธ์ธ</TitleMain>
<FormLogin onSubmit={onSubmit}>
<BoxInp>
<Label htmlFor="userEmail">
์ด๋ฉ์ผ
<Input
type="email"
id="userEmail"
required
{...register('email', { required: true, pattern: regExpEm })}
/>
</Label>
</BoxInp>
{errors?.email?.type === 'required' && (
<TxtError>* ์ด๋ฉ์ผ์ ์
๋ ฅํด์ฃผ์ธ์</TxtError>
)}
{errors?.email?.type === 'pattern' && (
<TxtError>* ์๋ชป๋ ์ด๋ฉ์ผ ํ์์
๋๋ค.</TxtError>
)}
<BoxInp>
<Label htmlFor="userPw">
๋น๋ฐ๋ฒํธ
<Input
type="password"
id="userPw"
required
{...register('password', { required: true, pattern: regExgPw })}
/>
</Label>
{errors?.password?.type === 'pattern' && (
<TxtError>
* ๋น๋ฐ๋ฒํธ๋ ์๋ฌธ(๋/์๋ฌธ์ ๊ตฌ๋ถ), ์ซ์ ์กฐํฉํ์ฌ 6~12์๋ฆฌ๋ก
์
๋ ฅํด ์ฃผ์ธ์.
</TxtError>
)}
{loginError && (
<TxtError>* ์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.</TxtError>
)}
</BoxInp>
<BtnLogin type="submit" disabled={!isValid}>
๋ก๊ทธ์ธ
</BtnLogin>
</FormLogin>
<Link href="/signup" passHref>
<LinkSignUp>์ด๋ฉ์ผ๋ก ํ์๊ฐ์
</LinkSignUp>
</Link>
</MainLoginEmail>
</>
);
};
์ฐธ๊ณ ๋งํฌ
์ต๊ณ ..