반응형
설치
yarn add redux react-redux redux-saga axios @reduxjs/toolkit
예제 코드
-
todoReducer.js
export const TODO_ACTION_TYPE = { FETCH_TODO_LIST_REQUEST: 'todo/FETCH_TODO_LIST_REQUEST', FETCH_TODO_LIST_SUCCESS: 'todo/FETCH_TODO_LIST_SUCCESS', FETCH_TODO_LIST_FAIL: 'todo/FETCH_TODO_LIST_FAIL', FETCH_TODO_REQUEST: 'todo/FETCH_TODO_REQUEST', FETCH_TODO_SUCCESS: 'todo/FETCH_TODO_SUCCESS', FETCH_TODO_FAIL: 'todo/FETCH_TODO_FAIL', }; const initialState = { isFetching: false, todoList: [], todo: {}, error: {}, }; const todoReducer = (state = initialState, action) => { switch (action.type) { case TODO_ACTION_TYPE.FETCH_TODO_LIST_REQUEST: return { isFetching: true, todoList: [], todo: {}, error: {} }; case TODO_ACTION_TYPE.FETCH_TODO_LIST_SUCCESS: return { ...state, isFetching: false, todoList: action.payload }; case TODO_ACTION_TYPE.FETCH_TODO_LIST_FAIL: return { ...state, isFetching: false, error: action.payload }; case TODO_ACTION_TYPE.FETCH_TODO_REQUEST: return { ...state, isFetching: true, todo: {}, error: {} }; case TODO_ACTION_TYPE.FETCH_TODO_SUCCESS: return { ...state, isFetching: false, todo: action.payload }; case TODO_ACTION_TYPE.FETCH_TODO_FAIL: return { ...state, isFetching: false, error: action.payload }; default: return state; } }; export default todoReducer;
-
todoSaga.js
import { call, put, select, takeLatest } from 'redux-saga/effects'; import axios from 'axios'; import { TODO_ACTION_TYPE } from './todoReducer'; const fetchTodoList = function* () { try { const response = yield call(() => axios.get(`https://jsonplaceholder.typicode.com/todos`)); yield put({ type: TODO_ACTION_TYPE.FETCH_TODO_LIST_SUCCESS, payload: response.data }); } catch (error) { yield put({ type: TODO_ACTION_TYPE.FETCH_TODO_LIST_FAIL, payload: error }); } }; const fetchTodo = function* (action) { const data = action.payload; const id = data[0].id; try { const response = yield call( (id) => axios.get(`https://jsonplaceholder.typicode.com/todos/${id}`), id, ); yield put({ type: TODO_ACTION_TYPE.FETCH_TODO_SUCCESS, payload: response.data }); } catch (error) { yield put({ type: TODO_ACTION_TYPE.FETCH_TODO_FAIL, payload: error }); } }; const printTodoState = function* () { const state = yield select(({ todoReducer }) => todoReducer); console.log('printTodoState', state); }; const todoSaga = [ takeLatest(TODO_ACTION_TYPE.FETCH_TODO_LIST_REQUEST, fetchTodoList), takeLatest(TODO_ACTION_TYPE.FETCH_TODO_LIST_SUCCESS, fetchTodo), takeLatest(TODO_ACTION_TYPE.FETCH_TODO_SUCCESS, printTodoState), ]; export default todoSaga;
-
todoStore.js
import createSagaMiddleware from 'redux-saga'; import { applyMiddleware, combineReducers, createStore } from 'redux'; import todoReducer from './todoReducer'; import { all } from 'redux-saga/effects'; import todoSaga from './todoSaga'; const createTodoStore = () => { const sagaMiddleware = createSagaMiddleware(); const store = createStore( combineReducers({ todoReducer, }), applyMiddleware(sagaMiddleware), ); sagaMiddleware.run(function* () { yield all([...todoSaga]); }); return store; }; export default createTodoStore;
-
index.js
import React from 'react'; import { Provider, useDispatch, useSelector } from 'react-redux'; import { TODO_ACTION_TYPE } from './todoReducer'; import createTodoStore from './todoStore'; const store = createTodoStore(); const Container = () => { const todo = useSelector(({ todoReducer }) => todoReducer.todo); const dispatch = useDispatch(); return ( <div> <button onClick={() => dispatch({ type: TODO_ACTION_TYPE.FETCH_TODO_LIST_REQUEST })}> try fetch </button> <div>{todo.title}</div> </div> ); }; const App = () => { return ( <Provider store={store}> <Container /> </Provider> ); }; export default App;
예제 코드 - with reduxjs
-
todoSlice.js
import { createSlice } from '@reduxjs/toolkit'; const initialState = { isFetching: false, todoList: [], todo: {}, error: {}, }; const todoSlice = createSlice({ name: 'todo', initialState, reducers: { fetchTodoList: (state, action) => { state.isFetching = true; state.todoList = []; state.todo = {}; state.error = {}; }, fetchTodoListSuccess: (state, action) => { state.isFetching = false; state.todoList = action.payload; }, fetchTodoListFail: (state, action) => { state.isFetching = false; state.error = action.payload; }, fetchTodo: (state, action) => { state.isFetching = true; state.todo = {}; state.error = {}; }, fetchTodoSuccess: (state, action) => { state.isFetching = false; state.todo = action.payload; }, fetchTodoFail: (state, action) => { state.isFetching = false; state.error = action.payload; }, }, }); export default todoSlice;
-
todoSaga.js
import { call, put, select, takeLatest } from 'redux-saga/effects'; import axios from 'axios'; import todoSlice from './todoSlice'; const handleFetchTodoList = function* () { try { const response = yield call(() => axios.get(`https://jsonplaceholder.typicode.com/todos`)); // put : dispatch와 동일한 효과 yield put(todoSlice.actions.fetchTodoListSuccess(response.data)); } catch (error) { yield put(todoSlice.actions.fetchTodoListFail(error)); } }; const handleFetchTodoListSuccess = function* (action) { const data = action.payload; const id = data[0].id; try { const response = yield call( (id) => axios.get(`https://jsonplaceholder.typicode.com/todos/${id}`), id, ); yield put(todoSlice.actions.fetchTodoSuccess(response.data)); } catch (error) { yield put(todoSlice.actions.fetchTodoFail(error)); } }; const handleFetchTodoSuccess = function* () { // select : useSelector와 동일한 효과 const state = yield select(({ todoReducer }) => todoReducer); console.log('handleFetchTodoSuccess', state); }; const todoSaga = [ // todoSlice의 fetchTodoList action을 dispatch하게되면 handleFetchTodoList generator function 호출 takeLatest(todoSlice.actions.fetchTodoList, handleFetchTodoList), // todoSlice의 fetchTodoListSuccess action을 dispatch하게되면 handleFetchTodoListSuccess generator function 호출 takeLatest(todoSlice.actions.fetchTodoListSuccess, handleFetchTodoListSuccess), // todoSlice의 fetchTodoSuccess action을 dispatch하게되면 handleFetchTodoSuccess generator function 호출 takeLatest(todoSlice.actions.fetchTodoSuccess, handleFetchTodoSuccess), ]; export default todoSaga;
-
todoStore.js
import createSagaMiddleware from 'redux-saga'; import { applyMiddleware, combineReducers, createStore } from 'redux'; import { all } from 'redux-saga/effects'; import todoSlice from './todoSlice'; import todoSaga from './todoSaga'; const rootSaga = function* () { yield all([...todoSaga]); }; const createTodoStore = () => { const sagaMiddleware = createSagaMiddleware(); const store = createStore( combineReducers({ todoReducer: todoSlice.reducer, }), applyMiddleware(sagaMiddleware), ); sagaMiddleware.run(rootSaga); return store; }; export default createTodoStore;
-
index.js
import React from 'react'; import { Provider, useDispatch, useSelector } from 'react-redux'; import createTodoStore from './todoStore'; import todoSlice from './todoSlice'; const store = createTodoStore(); const Container = () => { const todo = useSelector(({ todoReducer }) => todoReducer.todo); const dispatch = useDispatch(); return ( <div> <button onClick={() => dispatch(todoSlice.actions.fetchTodoList())}>try fetch</button> <div>{todo.title}</div> </div> ); }; const App = () => { return ( <Provider store={store}> <Container /> </Provider> ); }; export default App;
참고
반응형
'Development > React' 카테고리의 다른 글
[React] WebSocket (1) | 2020.12.30 |
---|---|
[React] react-redux (0) | 2020.12.30 |
[React] Library (0) | 2020.12.30 |
[React] react-testing-library (0) | 2019.12.29 |
[React] Enzyme (0) | 2019.12.28 |