📝 DAY 01 - 220518 (2)
- 리덕스 상태관리
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, key, value }), // form: register, login / key: username, password, passwordConfirm
);
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; // ex> state.register.username
}),
[INITIALIZE_FORM]: (state, { payload: form }) => ({
...state,
[form]: initialState[form],
}),
},
initialState,
);
export default auth;
redux-actions
의 createActions 함수. ({ form, key, value }) => ({ form, key, value })
와 같이 해줌.첫번째 인자로 들어가는 객체의 각 필드에 액션타입을 적어주고, 값으로는 state 업데이트함수를 넣어줌.
-> 여기서는 immer의 produce() 함수로 쉽게 (spread ... 없이) 불변성을 유지함
두번째 인자로는 초기 값인 initialState가 들어감.
produce
함수produce(state, (draft) => {
draft[form][key] = value; // ex> state.register.username
})
useDispatch
, useSelector
이용.지난 포스팅 참조 -
useDispatch
,useSelector
(state 조회)
src/containers 폴더 생성 후, auth/LoginForm 파일 생성.
containers/auth/LoginForm
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { changeField, initializeForm } from '../../modules/auth';
import AuthForm from '../../components/auth/AuthForm';
const LoginForm = () => {
// store.dispatch 사용하기 위해 가져옴
const dispatch = useDispatch();
// useSelector로 state.auth.login 을 가져옴. (state는 register, login 필드 존재)
const { form } = useSelector(({ auth }) => ({
form: auth.login,
}));
// input 변경시 이벤트
const onChange = (e) => {
const { value, name } = e.target;
// changeField 액션을 발생시킴. -> 인자로는 payload가 들어감.
dispatch(
changeField({
form: 'login',
key: name, // e.target.name 으로, username 또는 password
value,
}),
);
};
const onSubmit = (e) => {
e.preventDefault();
// 폼 제출시 👉 추후 작성예정.
};
useEffect(() => {
// initializeForm 액션 생성함수를 dispatch함. - payload는 login (form: login)
dispatch(initializeForm('login'));
}, [dispatch]);
return (
// props로 넘긴 login값에 따라 UI 변경됨.
<AuthForm
type="login"
// 🔻 새로운 props들 넘김
form={form}
onChange={onChange}
onSubmit={onSubmit}
/>
);
};
✅ 액션 발생(dispatch)시
dispatch(액션생성함수(payload))
를 해주면 됨
pages/LoginPage.js 수정
import AuthTemplate from '../components/auth/AuthTemplate';
import LoginForm from '../containers/auth/LoginForm';
const LoginPage = () => {
return (
<AuthTemplate>
<LoginForm />
</AuthTemplate>
);
};
export default LoginPage;
components/auth/AuthForm.js 수정
import styled from 'styled-components';
import palette from '../../lib/styles/palette';
import { Link } from 'react-router-dom';
import Button from '../common/Button';
...
const AuthForm = ({ type, form, onChange, onSubmit }) => {
const text = textMap[type];
return (
<AuthFormBlock>
<h3>{text}</h3>
<form onSubmit={onSubmit}>
<StyledInput
autoComplete="username"
name="username"
placeholder="아이디"
onChange={onChange}
value={form.username}
/>
<StyledInput
type="password"
autoComplete="new-password"
name="password"
placeholder="비밀번호"
onChange={onChange}
value={form.password}
/>
{type === 'register' && (
<StyledInput
autoComplete="new-password"
name="passwordConfirm"
placeholder="비밀번호 확인"
type="password"
onChange={onChange}
value={form.passwordConfirm}
/>
)}
<ButtonWithMarginTop teal fullWidth>
{text}
</ButtonWithMarginTop>
</form>
<Footer>
{type === 'login' ? (
<Link to="/register">회원가입</Link>
) : (
<Link to="/login">로그인</Link>
)}
</Footer>
</AuthFormBlock>
);
};
export default AuthForm;
const { form } = useSelector(({ auth }) => ({
form: auth.login,
}));
form
은 state, 즉 auth.login
이므로 username, password 필드를 가진 객체이다.login: {
username: '',
password: '',
},
containers/RegisterForm.js
import { 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, // value: e.target.value
}),
);
};
const onSubmit = (e) => {
e.preventDefault();
// 폼 제출시
};
useEffect(() => {
dispatch(initializeForm('register'));
}, [dispatch]);
return (
<AuthForm
type="register"
form={form}
onChange={onChange}
onSubmit={onSubmit}
/>
);
};
export default RegisterForm;
마찬가지로 RegisterPage 렌더링을 바꿔줌.
pages/RegisterPage.js
import AuthTemplate from '../components/auth/AuthTemplate';
import RegisterForm from '../containers/auth/RegisterForm';
const RegisterPage = () => {
return (
<AuthTemplate>
<RegisterForm />
</AuthTemplate>
);
};
export default RegisterPage;
스토어에 잘 저장됨!
우선 여기까지 진행 과정 복습하기.
내일은 redux 미들웨어인 redux-saga 로 API 연동 + 회원가입 / 로그인 구현