맛집 앱 만들기 프로젝트 Part9 로그인 데이터 유효성 검증 및 리팩토링
useForm 훅 구현하기
[matzip/front/src/hooks/useForm.ts]
리액트에서 훅은 v16.8에 새로 도입된 기능으로, 함수형 컴포넌트(Functional Component)에서 사용되는 몇가지 기술들을 일컫는다. 리액트 훅은 함수형 컴포넌트(Functional Component)가 클래스형 컴포넌트(Class Component)의기능을 사용 할 수 있도록 해주며 대표적인 예로는 useState, useEffect 등이 존재한다
해당 훅을 사용하여 로그인페이지등에서 사용자가 입력한 input 데이터를 가공하는 작업을 진행한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import {useEffect, useState} from 'react';
// useForm의 규격 정의
// initialValue는 email, password 데이터의 객체값
// validate는 email, password 데이터를 정규식으로 검사후 리턴 받은 객체값
interface UseFormProps<T> {
initialValue: T;
validate: (values: T) => Record<keyof T, string>;
}
// values는 email, password 데이터의 객체값
// touched는 true,false의 값을 갖고있으며 사용자가 해당 input박스를 터치했는지 확인
// errors는 정규식에 따른 이메일, 패스워드 검사 결과 에러메세지를 담는 객체
function useForm<T>({initialValue, validate}: UseFormProps<T>) {
const [values, setValues] = useState(initialValue);
const [touched, setTouched] = useState<Record<string, boolean>>({});
const [errors, setErrors] = useState<Record<string, string>>({});
// 밑에서 정의한 getTextInputProps 함수에 의해서 발동되는 핸들러로 사용자로부터 받은 입력데이터를 values라는 객체에 담는다
const handleChangeText = (name: keyof T, text: string) => {
console.log(name);
setValues({
...values,
[name]: text,
});
};
// 밑에서 정의한 getTextInputProps 함수에 의해서 발동되는 핸들러로 사용자가 해당 input값을 터치했는지를 감지한다
const handleBlur = (name: keyof T) => {
setTouched({
...touched,
[name]: true,
});
};
// input에서 입력할때마다 호출되는 함수로 위에 정의한 value, onChangeText, onBlur 값을 저장 및 리턴하기 위한 함수이다
const getTextInputProps = (name: keyof T) => {
const value = values[name];
const onChangeText = (text: string) => handleChangeText(name, text);
const onBlur = () => handleBlur(name);
return {value, onChangeText, onBlur};
};
// 렌더링이 될때마다, 값이 바뀔 때마다 사용되는 훅으로 값이 들어올대마다 validate 컴포넌트를 통해 검사후 에러메세지를 newErrors에 담는다
useEffect(() => {
const newErrors = validate(values);
setErrors(newErrors);
}, [validate, values]);
return {values, errors, touched, getTextInputProps};
}
export default useForm;
유효성 검증 컴포넌트 구현하기
[matzip/front/src/utils/validate.ts]
사용자가 입력한 데이터 유효성을 검사하는 컴포넌트로 단순 정규식과 비교하여 에러메세지를 리턴할 수 있도록 구현하였다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type UserInfomation = {
email: string;
password: string;
};
function validateLogin(values: UserInfomation) {
const errors = {
email: '',
password: '',
};
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) {
errors.email = '올바른 이메일 형식이 아닙니다.';
}
if (!(values.password.length >= 8 && values.password.length <= 20)) {
errors.password = '비밀번호는 8~20자 사이로 입력해주세요.';
}
return errors;
}
export {validateLogin};
로그인 스크린 수정
[matzip/front/src/screens/LoginScreens.ts]
로그인 화면 페이지를 수정하여 위에서 구현한 유효성검사와 입력데이터 훅을 사용하여 처리해보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import React from 'react';
import {SafeAreaView, StyleSheet, View} from 'react-native';
import InputField from '../../components/InputField';
import CustomButton from '../../components/CustomButton';
import useForm from '../../hooks/useForm';
import {validateLogin} from '../../utils';
// 만들어둔 useForm 훅에 email과 password의 초기값 객체 전달 및 유효성 검증 함수 전달
function LoginScreen() {
const login = useForm({
initialValue: {email: '', password: ''},
validate: validateLogin,
});
// 아직은 미구현으로 단순 로그인 버튼을 눌렀을때 console.log로 사용자가 입력한 아이디와 비밀번호를 출력하도록 임시 구현
const handleSubmit = () => {
console.log('login.values', login.values);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.inputContainer}>
<InputField
placeholder="이메일"
error={login.errors.email}
touched={login.touched.email}
inputMode="email"
{...login.getTextInputProps('email')}
/>
<InputField
placeholder="비밀번호"
error={login.errors.password}
touched={login.touched.password}
secureTextEntry
{...login.getTextInputProps('password')}
/>
</View>
<CustomButton
label="로그인"
variant="filled"
size="large"
onPress={handleSubmit}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
margin: 30,
},
inputContainer: {
gap: 20,
marginBottom: 30,
},
});
export default LoginScreen;
유효성 검사를 적용한 앱화면
This post is licensed under
CC BY 4.0
by the author.