Redux reducer는 side effects를 포함할 수 없다.
side effects란 함수의 반환 값 외에 볼 수 있는 상태/동작의 모든 변경 사항이다.
Ex.
- 콘솔에 값 로깅
- 파일 저장
- 비동기 타이머 설정
- AJAX HTTP 요청
- 함수 외부에 존재하는 일부 상태를 수정하거나 함수에 대한 인수 변경
- 난수 또는 고유한 난수 id 생성
이러한 Side effects는 Redux Middleware에서 수행될 수 있다.
대표적으로 상태에 관해 외부 Server에 http request로 받은 데이터를 fetch하여 들고오는 경우 비동기 처리를 하여야 한다.
비동기 middleware 함수를 action 객체가 아니라 dispatch로 넘겨, dispatch 전에 middleware가 먼저 실행될 수 있도록 한다.
Redux의 공식 async function middleware
npm install redux-thunk
dispatch와 getState를 인수로 받는 함수로, 어떤 Redux store가 사용되는지 알지 못하는 채로 비동기 로직을 미리 작성할 수 있다.
Ex.
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import './index.css'
import App from './App'
import './api/server'
import store from './store'
import { fetchTodos } from './features/todos/todosSlice'
store.dispatch(fetchTodos)
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
// store에 thunk 사용할 수 있도록 update
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducer'
const composedEnhancer = composeWithDevTools(applyMiddleware(thunkMiddleware))
// The store now has the ability to accept thunk functions in `dispatch`
const store = createStore(rootReducer, composedEnhancer)
export default store
// thunk function
import { client } from '../../api/client'
const initialState = []
export default function todosReducer(state = initialState, action) {
switch (action.type) {
// omit other reducer cases
case 'todos/todosLoaded': {
// Replace the existing state entirely by returning the new value
return action.payload
}
default:
return state
}
}
// thunk function
export async function fetchTodos(dispatch, getState) {
const response = await client.get('/fakeApi/todos')
dispatch({ type: 'todos/todosLoaded', payload: response.todos })
}
https://redux.js.org/tutorials/fundamentals/part-6-async-logic
https://redux.js.org/tutorials/fundamentals/part-7-standard-patterns
https://redux.js.org/tutorials/fundamentals/part-8-modern-redux