import { createAction, handleActions } from "redux-actions";
import { call, put, takeLatest } from "redux-saga/effects";
import * as api from "../lib/api";
const GET_POST = "leader/GET_POST"; // post 를 요청하는 액션
const GET_POST_SUCCESS = "leader/GET_POST_SUCCESS"; // post 요청 성공 시 데이터(post)를 전달하는 액션
const GET_POST_FAILURE = "leader/GET_POST_FAILURE"; // post 요청 실패 시 처리하는 액션
const GET_USERS = "leader/GET_USERS"; // users 를 요청하는 액션
const GET_USERS_SUCCESS = "leader/GET_USERS_SUCCESS"; // users 요청 성공 시 데이터(users) 를 전달하는 액션
const GET_USERS_FAILURE = "leader/GET_USERS_FAILURE"; // users 요청 실패 시 처리하는 액션
export const getPost = createAction(GET_POST, (id) => id); // payload가 id인 액션객체 생성
export const getUsers = createAction(GET_USERS); // payload가 없는 액션객체 생성
// state 의 초기값 설정
const initialState = {
post: null,
users: null,
};
//** Redux **//
// post/users 요청 성공 시 Data 처리하는 redux만 정의
// post/users 요청 실패 시 처리할 데이터 없음
// post/users 요청 액션은 Saga에서 수행
const leader = handleActions(
{
[GET_POST_SUCCESS]: (state, action) => ({
...state,
post: action.payload,
}),
[GET_USERS_SUCCESS]: (state, action) => ({
...state,
users: action.payload,
}),
},
initialState
);
export default leader;
//** Saga **//
// GET_POST/GET_USERS 액션에 대한 서버요청을 위한 Saga
export function* leaderSaga() {
yield takeLatest(GET_POST, getPostSaga);
yield takeLatest(GET_USERS, getUsersSaga);
}
// GET_POST 액션 dispatch 시 실행될 함수. 비동기로 서버의 post 데이터 요청
function* getPostSaga(action) {
try {
const post = yield call(api.getPost, action.payload);
// post 데이터요청하는 비동기함수인 getPost을 요청하며, 인자로 action.payload인 id를 넘김
yield put({
type: GET_POST_SUCCESS, // 요청 성공 액션을 dispatch함.
payload: post.data, // 액션 dispatch할 때 payload로 post.data(포스트 내용)을 전달함
});
} catch (e) {
yield put({
type: GET_POST_FAILURE, // 요청 실패 액션을 dispatch함
payload: e, // 액션 dispatch할 때 payload로 에러를 전달함
error: true, // 액션 객체의 항목에 error: true를 넘겨줌
});
}
}
// GET_USERS 액션 dispatch 시 실행될 함수. 비동기로 서버의 users 데이터 요청
function* getUsersSaga() {
try {
const users = yield call(api.getUsers);
// users 데이터를 요청하는 비동기함수인 getUsers를 요청하며, 전달인자는 없음.
yield put({
type: GET_USERS_SUCCESS,
payload: users.data,
});
} catch (e) {
yield put({
type: GET_USERS_FAILURE,
payload: e,
error: true,
});
}
}
(3) src/modules/index.js
reducer, saga 를 통합해줍니다.
import { combineReducers } from "redux";
import leader, { leaderSaga } from "./leader";
import { all } from "redux-saga/effects";
const rootReducer = combineReducers({
leader,
});
export default rootReducer;
export function* rootSaga() {
yield all([leaderSaga()]);
}
(4) src/index.js (스토어 생성)
Saga를 불러오고, Saga를 포함한 미들웨어를 적용하여 스토어를 생성하고, Saga를 실행합니다.
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import createSagaMiddleware from "@redux-saga/core";
import { applyMiddleware, createStore } from "redux";
import rootReducer, { rootSaga } from "./modules";
import { composeWithDevTools } from "redux-devtools-extension";
import { Provider } from "react-redux";
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(sagaMiddleware))
);
sagaMiddleware.run(rootSaga);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
(5) src/containers/LeaderContainer.jsx
이제 데이터를 받아올 통로는 만들어졌으므로, 데이터를 실제 요청하고, 받은 데이터는 하위로 보내주는 데이터 담당 Container를 작성합니다.
import React from "react";
import { connect } from "react-redux";
import Leader from "../components/Leader";
import { getPost, getUsers } from "../modules/leader";
import { useEffect } from "react";
const LeaderContainer = ({ getPost, getUsers, post, users }) => {
useEffect(() => {
getPost(1); // 액션 생성함수 실행('leader/GET_POST' 액션타입, payload: id=1)
getUsers(); // 액션 생성함수 실행
}, [getPost, getUsers]); // getPost ,getUsers에 변경이 있을 시 마다 호출
return <Leader post={post} users={users} />;
};
export default connect(
({ leader }) => ({
// props로 전달해 줄 post/users에, state의 leader에서 각각의 값 추출하여 전달
post: leader.post,
users: leader.users,
}),
{
getPost, // props로, dispatch 함수 중 Post요청 액션생성함수 전달
getUsers, // props로, dispatch 함수 중 Users요청 액션생성함수 전달
}
)(LeaderContainer);