이제 리듀서를 구현해 볼 차례이다.
리듀서는 reducers 폴더 안에 index.js를 생성하여 작업하며 rootReducer를 기존에 만들었던store(configureStore)에 적용하여 구현한다. 리듀서는 초기값(initialState), 액션함수, 리듀서로 구성되어있다. (아래 코드 참고)
이렇게 만들어진 액션 함수를 각 컴포넌트에서 store.dispatch(login("wonny"));
와 같은 방법으로
사용하면 해당 액션을 디스패치하고 있던 모든 컴포넌트에 데이터 업데이트가 발생한다.
/reducers/index.js
const { HYDRATE } from "next-redux-wrapper";
// initial state
const initialState = {
user: {
isLoggedIn: false,
user: null,
signUpData: {},
loginData: {},
},
post: {
mainPosts: [],
},
};
// Action Creator
export const loginAtion = (data) => ({ type: "LOG_IN", data });
export const logoutAction = () => ({ type: "LOG_OUT" });
// Reducer
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case HYDRATE :
return { ...state, ...action.payload }; // 이후 수업에서 배운다.
case "LOG_IN":
return {
...state,
user: {
...state.user,
isLoggedIn: true,
user: action.data,
},
};
case "LOG_OUT":
return {
...state,
user: {
...state.user,
isLoggedIn: false,
user: null,
},
};
// 초기 렌더링 시 리듀서가 실행되면서 state가 Undefined된다.
// 따라서 초기 default 값으로 initialState를 리턴해준다.
default:
return state;
}
};
export default rootReducer;
이제 위 설정에 따라 실제 컴포넌트에 리덕스를 적용해볼 차례이다. 해당 작업 전 react-redux를 설치해주자
$ npm i react-redux
/container/AppLayout.js
import React from "react";
import { useSelector } from "react-redux";
import UserProfile from "../components/UserProfile";
import LoginForm from "../components/LoginForm";
const AppLayout = ({ children }) => {
const isLoggedIn = useSelector((state) => state.user.user.isLoggedIn);
return (
<div>
<Row gutter={8}>
<Col xs={24} md={6}>
{isLoggedIn ? <UserProfile /> : <LoginForm />}
</Col>
</Row>
</div>
);
};
export default AppLayout;
기존의 useState 구문이 모두 redux로 대체되면서 UserProfile, LoginForm에 상속해주던 setState 함수도 모두 삭제 처리해준다. state를 가져올 때에는 useSelector로 state를 가져오면 된다.
하위 컴포넌트들은 모두 useDispatch를 통해 action이 발생하도록 처리해준다.
/container/LoginForm
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { loginAction } from "../reducers";
const LoginForm = () => {
const dispatch = useDispatch();
// action Dispatch
const onSubmitForm = useCallback(() => dispatch(loginAction({ id, password })), [id, password]);
return (
<FormWrapper onFinish={onSubmitForm}>
{/* ...codes */}
</FormWrapper>
);
};
export default LoginForm;
/container/UserProfile
import React, { useCallback } from "react";
import { Card, Avatar, Button } from "antd";
import { useDispatch } from "react-redux";
import { logoutAction } from "../reducers";
const UserProfile = () => {
const dispatch = useDispatch();
const onLogout = useCallback(() => dispatch(logoutAction()), []);
return (
<>
{/* ...codes */}
<Button onClick={onLogout}>로그아웃</Button>
</>
);
};
export default UserProfile;