일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 참조형변수
- 사용자예외클래스생성
- 환경설정
- 대덕인재개발원
- abstract
- 객체 비교
- EnhancedFor
- 다형성
- 추상메서드
- 예외처리
- 제네릭
- exception
- 예외미루기
- 인터페이스
- 정수형타입
- 오라클
- 자동차수리시스템
- 생성자오버로드
- 메소드오버로딩
- oracle
- Java
- cursor문
- GRANT VIEW
- 컬렉션 타입
- 한국건설관리시스템
- 집합_SET
- 어윈 사용법
- 자바
- 컬렉션프레임워크
- NestedFor
- Today
- Total
거니의 velog
(3) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 3 본문
(2) 리덕스로 폼 상태 관리하기
* 이번에는 리덕스로 회원가입과 로그인 폼의 상태를 관리하는 방법을 알아보자. 이전에 만들어 놓았던 auth 모듈을 다음과 같이 수정해 보자.
[modules/auth.js]
import { createAction, handleActions } from 'redux-actions';
import produce from 'immer';
const CHANGE_FIELD = 'auth/CHANGE_FIELD';
const INITIALIZE_FORM = 'auth/INITIALIZE_FORM';
export const changeField = createAction(
CHANGE_FIELD,
({ form, key, value }) => ({
form, // register , login
key, // username, password, passwordConfirm
value, // 실제 바꾸려는 값
}),
);
export const initializeForm = createAction(INITIALIZE_FORM, (form) => form); // register / login
const initialState = {
register: {
username: '',
password: '',
passwordConfirm: '',
},
login: {
username: '',
password: '',
},
};
const auth = handleActions(
{
[CHANGE_FIELD]: (state, { payload: { form, key, value } }) =>
produce(state, (draft) => {
draft[form][key] = value; // 예: state.register.username을 바꾼다
}),
[INITIALIZE_FORM]: (state, { payload: form }) => ({
...state,
[form]: initialState[form],
}),
},
initialState,
);
export default auth;
* 이제 컨테이너 컴포넌트를 만들어 보자. src 디렉터리에 containers 디렉터리를 만든 후 다양한 컨테이너 컴포넌트들을 종류별로 분류하여 만들어 보겠다.
* 앞으로 만든 컨테이너 컴포넌트에서는 useDispatch와 useSelector 함수를 사용하여 컴포넌트를 리덕스와 연동시킨다. 앞으로 이 프로젝트에서 작성할 모든 컨테이너 컴포넌트는 connect 함수 대신 Hooks를 사용하여 구현할 것이다.
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { changeField, initializeForm } from '../../modules/auth';
import AuthForm from '../../components/auth/AuthForm';
const LoginForm = () => {
const dispatch = useDispatch();
const { form } = useSelector(({ auth }) => ({
form: auth.login,
}));
// 인풋 변경 이벤트 핸들러
const onChange = (e) => {
const { value, name } = e.target;
dispatch(
changeField({
form: 'login',
key: name,
value,
}),
);
};
// 폼 등록 이벤트 핸들러
const onSubmit = (e) => {
e.preventDefault();
// 구현 예정
};
// 컴포넌트가 처음 렌더링될 때 form을 초기화함
useEffect(() => {
dispatch(initializeForm('login'));
}, [dispatch]);
return (
<AuthForm
type="login"
form={form}
onChange={onChange}
onSubmit={onSubmit}
/>
);
};
export default LoginForm;
* 위 컴포넌트에서는 onChange 함수와 onSubmit 함수를 구현하여 필요한 액션을 디스패치하도록 구현해 주었다. 또한, useEffect를 사용하여 맨 처음 렌더링 후 initializeForm 액션 생성 함수를 호출했다. 이 작업을 하지 않으면, 로그인 페이지에서 값을 입력한 뒤 다른 페이지로 이동했다가 다시 돌아왔을 때 값이 유지된 상태로 보이게 된다.
* 이 컨테이너 컴포넌트를 다 만든 뒤에는 LoginPage에서 기존 Authform을 LoginForm으로 대체시키자.
[pages/LoginForm.js]
import React from 'react';
import AuthTemplate from '../components/auth/AuthTemplate';
import LoginForm from '../containers/auth/LoginForm';
const LoginPage = () => {
return (
<AuthTemplate>
<LoginForm />
</AuthTemplate>
);
};
export default LoginPage;
* 다음으로는 컨테이너에서 props로 넣어 주었던 onChange, onSubmit, form 값을 사용할 것이다.
[components/auth/AuthForm.js]
const AuthForm = ({ type, form, onChange, onSubmit }) => {
const text = textMap[type]; // 타입(login, register)에 따라 출력되는 text의 값이 다르다.
return (
<AuthFormBlock>
<h3>{text}</h3>
<form onSubmit={onSubmit}>
<StyledInput
autoComplete="username"
name="username"
placeholder="아이디"
onChange={onChange}
value={form.username}
/>
<StyledInput
autoComplete="new-password"
name="password"
placeholder="비밀번호"
type="password"
onChange={onChange}
value={form.password}
/>
{type === 'register' && (
<StyledInput
autoComplete="new-password"
name="passwordConfirm"
placeholder="비밀번호 확인"
type="password"
onChange={onChange}
value={form.passwordConfirm}
/>
)}
<ButtonWithMarginTop cyan fullWidth style={{ marginTop: '1rem' }}>
{text}
</ButtonWithMarginTop>
</form>
<Footer>
{type === 'login' ? (
<Link to="/register">회원가입</Link>
) : (
<Link to="/login">로그인</Link>
)}
</Footer>
</AuthFormBlock>
);
};
export default AuthForm;
* 코드를 저장한 뒤 http://localhost:3000/login 페이지에 가 보세요. 그리고 인풋에 텍스트를 입력하고 나서 값이 리덕스 스토어에 잘 들어가는지 개발자 도구를 통해 확인해 보세요.
* 만약 회원가입 페이지를 보고 있다면 form 값이 없어서 에러가 발생할 것이다. 회원가입 페이지의 에러는 나중에 수정하겠다.
* 이제 RegisterForm 컴포넌트도 구현하겠다. LoginForm 컴포넌트를 복사한 뒤 내부에서 사용되는 키워드만 [Login > Register], [login -> register]로 고쳐 주면 된다.
[components/auth/RegisterForm.js]
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { changeField, initializeForm } from '../../modules/auth';
import AuthForm from '../../components/auth/AuthForm';
const RegisterForm = () => {
const dispatch = useDispatch();
const { form } = useSelector(({ auth }) => ({
form: auth.register,
}));
// 인풋 변경 이벤트 핸들러
const onChange = (e) => {
const { value, name } = e.target;
dispatch(
changeField({
form: 'register',
key: name,
value,
}),
);
};
// 폼 등록 이벤트 핸들러
const onSubmit = (e) => {
e.preventDefault();
// 구현 예정
};
// 컴포넌트가 처음 렌더링될 때 form을 초기화함
useEffect(() => {
dispatch(initializeForm('register'));
}, [dispatch]);
return (
<AuthForm
type="register"
form={form}
onChange={onChange}
onSubmit={onSubmit}
/>
);
};
export default RegisterForm;
* 이제 RegisterPage에서 사용 중이던 AuthForm을 RegisterForm으로 교체하자.
[pages/RegisterPage.js]
import React from 'react';
import AuthTemplate from '../components/auth/AuthTemplate';
import RegisterForm from '../containers/auth/RegisterForm';
const RegisterPage = () => {
return (
<AuthTemplate>
<RegisterForm />
</AuthTemplate>
);
};
export default RegisterPage;
* 코드를 작성한 뒤 회원가입 폼에서 값을 입력할 때 리덕스에 값이 잘 반영되는지 확인해 보자.
'React > React_프론트엔드 프로젝트' 카테고리의 다른 글
(6) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 6 (0) | 2024.02.22 |
---|---|
(5) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 5 (0) | 2024.02.22 |
(4) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 4 (0) | 2024.02.22 |
(2) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 2 (0) | 2024.02.21 |
(1) 프론트엔드 프로젝트 : 시작 및 회원 인증 구현 1 (0) | 2024.02.21 |