일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 웹
- 공부
- await
- 자동반영
- 리사이클러뷰
- 가상회선교환
- list
- redux
- hot Reloading
- pull
- react
- merge
- Git
- 리액트
- equalityFn
- async
- 리덕스
- Kotlin
- createPortal
- 비동기처리
- list.map
- useCallback
- 컬러구성
- useState
- rebase
- javascript
- php문법
- typescript
- CSS
- 리액트를 다루는 기술
- Today
- Total
공부블로그
리덕스 미들웨어 redux-thunk 본문
에러땜에 짱 고생한 redux-thunk를 정리해보게따....
저번에 redux로 만든 todo-app redux에 middleware중 하나인 redux-thunk를 적용하는 코드를 작성해보자.
아 그리고 change_status 액션도 하나 더 만들었다.
redux-thunk 는 뭘 하는 미들웨어일까? (from. 벨로퍼트 깃북)
가장 간단히 설명하자면, 이 미들웨어는 객체 대신 함수를 생성하는 액션 생성함수를 작성 할 수 있게 해줍니다. 리덕스에서는 기본적으로는 액션 객체를 디스패치합니다. 일반 액션 생성자는, 다음과 같이 파라미터를 가지고 액션 객체를 생성하는 작업만합니다:
만약에 특정 액션이 몇초뒤에 실행되게 하거나, 현재 상태에 따라 아예 액션이 무시되게 하려면, 일반 액션 생성자로는 할 수가 없습니다. 하지만, redux-thunk 는 이를 가능케합니다.
간단하게 정리를 하자면 redux-thunk 는 일반 액션 생성자에 날개를 달아줍니다. 보통의 액션생성자는 그냥 하나의 액션객체를 생성 할 뿐이지만 redux-thunk 를 통해 만든 액션생성자는 그 내부에서 여러가지 작업을 할 수 있습니다. 이 곳에서 네트워크 요청을 해도 무방하죠. 또한, 이 안에서 액션을 여러번 디스패치 할 수도 있습니다.
예를 들어, 할일이 완료된 상태일 때만 삭제가 가능하게 만들고 싶다! 라고 한다면,
- 우선 리듀서에 '아이템 삭제 액션'이 왔을 때 어떻게 값을 변경할 지 구현해 놓는다.
- 그런데 나는 완료된 상태일 때만 삭제하는 액션을 생성할거니까 중간에서 '아이템 삭제 액션'을 생성할지 말지 if문으로 걸러야한다.
- 이때, thunk action을 사용한다!
- 그러면 전체흐름은 1. 삭제를 누르면 thunk action을 생성한다 2. 해당 액션에서 '아이템 삭제 액션'을 dispatch하거나 말거나 한다.
그럼 코드를 작성해보자!
1. 미들웨어를 적용하기 위해서 우선 redux-thunk를 설치해야한다. redux-toolkit도 설치하는 게 좋다.
npm install redux-thunk
2. 진짜 빡치는 부분
원래는 useDispatch로 thunk action까지 만들 수 있었는데 지금은 안된단다;; (어이업써)
그래서 thunk액션을 위한 타입과 hook을 새로 만들어줘야한다.
완벽히 이해하지는 못했는데 stackoverflow에서 긁어왔다.
긍데 뜬금없이 느끼는 거지만 vscode는 참 설명을 잘해주네
(index.tsx)
import { configureStore } from '@reduxjs/toolkit' //리덕스 createStore()가 없어져서 이걸로 써야함
import { AnyAction } from 'redux';
import thunk, { ThunkDispatch } from 'redux-thunk';
import { Provider, useDispatch } from 'react-redux';
import rootReducer, { RootState } from './modules'
//thunk 미들웨어를 사용하고, 생성했던 루트리듀서를 사용하는 스토어를 만들어준다.
const store = configureStore({reducer: rootReducer, middleware: [thunk]});
//ThunkDispatch라는 함수형 인터페이스를 사용해야 thunk action을 dispatch(생성)할 수 있다.
export type AppThunkDispatch = ThunkDispatch<RootState, any, AnyAction>;
//thunk 액션에도 사용할 수 있는 hook인 useAppDispatch를 만든다...(문법은 잘 모르게씀)
export const useAppDispatch = () => useDispatch<AppThunkDispatch>();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
//Provider의 파라미터로 전달
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>
);
reportWebVitals();
3. 액션 정의하기 (thunk action도)
import { todoItem } from '../../App'
import { Action, createAction} from "typesafe-actions";
import { ThunkAction } from 'redux-thunk';
import { RootState } from '..';
//Ation 정의 (리덕스 액션에 들어갈)
export const ADD_TODO = "todo/ADD_TODO";
export const CHANGE_STATUS = 'todo/CHANGE_STATUS'
export const DELETE_TODO = "todo/DELETE_TODO";
//Action 생성 함수 구현
// 첫번째 인자: Action Type, 두번째 인자: payload(액션함수의 파라미터), 세번째 인자: Action Type인데 자동으로 적용
export const addTodo = createAction(ADD_TODO)<{todo: todoItem;}>();
export const changeStatus = createAction(CHANGE_STATUS)<{id : number;}>();
export const deleteTodo = createAction(DELETE_TODO)<{id: number;}>();
//thunk action 생성 함수 구현
export const deleteTodoThunk = (id: number): ThunkAction<void, RootState, null, Action> => {
return (dispatch, getState) => {
const list = getState().todo.todo
//id가 해당 번호인 값의 상태가 참이면 삭제 dispatch
list.forEach((val)=>{
if((val.id === id)&&(val.status === true)){
dispatch(deleteTodo({id : id}))
}
})
}
}
4. 원래 삭제버튼을 누르면 바로 '아이템 삭제 액션'을 dispatch 했지만 이제는 'thunk action'을 dispatch한다.
내가 따로 만든 thunk action용 useAppDispatch( )를 불러와서 사용해야한다.
import { useSelector } from 'react-redux';
import { RootState } from './modules';
import { useDispatch } from 'react-redux';
import { deleteTodo, deleteTodoThunk } from './modules/todos/actions';
//내가 만든 thunk action dispatch용 Hook을 불러온다
import { useAppDispatch } from '.';
function App() : React.ReactElement {
const reduxTodoList = useSelector((state: RootState) => state.todo.todo)
//thunk action용 dispatch Hook
const dispatch = useAppDispatch();
return (
<div className="App">
<Input/>
{reduxTodoList.map((val: todoItem)=>
<div style={{display: 'flex'}} key={val.id}>
<Item
id={val.id}
title = {val.title}
date = {val.date}
status = {val.status}
/>
<button onClick={()=> {
dispatch(deleteTodoThunk(val.id));
}}>삭제</button>
</div>
)}
</div>
);
}
export default App;
끝!
흐름을 이해한 걸로 만족해보기로 한다...ㅎ
'리액트 > 리액트 공부' 카테고리의 다른 글
Props를 useState의 초기값으로 넣었을 때의 문제 (0) | 2022.12.20 |
---|---|
Recoil 상태 관리 라이브러리 (0) | 2022.09.20 |
리덕스 (with typesafe-actions) (1) | 2022.09.19 |
리액트 진짜 초급 강의 (0) | 2022.04.14 |
리액트 Router DOM 사용하기 (0) | 2021.08.01 |