개발/ReactJS
useForm 사용하여 로그인 & 회원가입 구현 - 1.로그인
8시20분
2021. 11. 4. 08:20
기존 프로젝트의 회원가입 & 로그인은 아래와 같이 global state로 유저 email, 비밀번호, 이름 등의 정보를 관리하여 한번에 signup 혹은 login API를 호출할 때, body에 json 형태로 담아 호출하는 방식으로 진행하였다.
//ridge.ts
export const signupState = newRidgeState({
email: '',
password: '',
name: '',
username: '',
hiddenUsername: '',
description: '',
});
//signupPage.tsx
const SignUpPage = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [valid, setValid] = useState<boolean>(true);
const [validPassword, setValidPassword] = useState<boolean>(true);
............ 생략 ............
<Button
tw={{ borderRadius: 'rounded-2xl' }}
variant="outlined"
disabled={!email || !password || !valid || !validPassword}
onClick={async () => {
await signupState.set((prev) => ({
...prev,
email,
password,
}));
>
Sign up
</Button>
}
global state로 관리하는 방식의 경우, 각 페이지 마다 값을 저장하고 있는 state들이 많아서 코드의 유지보수 및 가시성이 떨어지는 단점이 생기는데 React-Hook-Form의 useForm을 사용하면, 이러한 문제를 해결할 수 있다.
1. FormValues의 구성 요소 타입 지정하기
아래와 같이 로그인에 필요한 구성 요소(email 혹은 id, password)의 데이터 타입을 interface 형태로 지정해준다.
interface FormValues {
email: string;
password: string;
}
2. LoginPage안에 useForm 선언하기
아래와 같이 LoginPage 안에 useForm을 선언하고 타입은 1에서 지정한 FormValues를 활용한다.
export const LoginPage = () => {
const {
setError,
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
return(
<>로그인 페이지</>
);
}
3. LoginPage에 <Form 태그> 추가하기
2에서 했던 LoginPage에 <form></form>의 형식으로 로그인 Form을 구성한다. form 태그의 속성중 onSubmit를 사용하여 버튼 onClick 이벤트 시 onSubmit에 위치한 로그인 API를 호출하게 한다.
export const LoginPage = () => {
const {
setError,
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
........ 생략 ........
return (
<form
className="p-4 flex flex-col space-y-4"
onSubmit={handleSubmit((data) => {
api
.post('/users/valid-email-login', { email: data.email })
.then(() =>
login(data)
.then(() => push('/'))
.catch(
(e) =>
e.response.status === 401 &&
setError('password', {
message: '*비밀번호가 잘못되었습니다.',
})
)
)
.catch(
(e) =>
e.response.status === 409 &&
setError('email', { message: '*가입된 이메일이 아닙니다.' })
);
})}
>
<TextField
label="이메일"
type="email"
placeholder="이메일을 입력해주세요."
helper={errors.email?.message}
{...register('email', { required: '이메일을 입력해주세요' })}
/>
<TextField
label="비밀번호"
type="password"
placeholder="비밀번호를 입력해주세요."
helper={errors.password?.message}
{...register('password', { required: '비밀번호를 입력해주세요' })}
/>
<Button text="로그인" className="filled-brand-2" />
<Button to="/signup" text="회원가입" className="bg-gray-100" />
</form>
)
}