리덕스에서 관리해야 할 state가 많아질 때
생길 수 있는 문제점
1. 액션 타입
액션을 dispatch할 때 type에 오타가 나서는 안된다.
여럿이서 작업하다보면 많은 type 식별자가 생길 수 있는데
그러다 보면 type 식별자가 충돌이 날 수 있다.
해결 방안 1.
import { createStore } from "redux";
export const INCREMENT = "increment";
const initialState = { counter: 0, showCounter: true };
const counterReducer = (state = initialState, action) => {
if (action.type === INCREMENT) {
return {
counter: state.counter + 1,
showCounter: state.showCounter,
};
}
상수를 export해서 그것을 reducer function에서 사용한다.
그리고 그걸 Counter 컴포넌트에서도 사용한다.
import { INCREMENT } from "../store/index";
const Counter = () => {
...
const incrementHandler = () => {
dispatch({ type: INCREMENT });
};
해결방안 2. Redux toolkit 라이브러리 사용하기
꼭 사용해야만 하는 건 아니다....
react-redux나 redux는 꼭 설치해야만 했지만.
그래도 사용해보자!
Redux toolkit 사용하기
1. redux tookit 설치
npm install @reduxjs/toolkit
을 터미널에서 입력한다.
그리고 리덕스 라이브러리를 언인스톨 해야한다.
(Redux toolkit에 이미 포함되어 있기 때문)
2. 리덕스 package.json에서 지우기
3. redux 사용하기
1) createSlice import하기
https://redux-toolkit.js.org/api/createslice
createSlice | Redux Toolkit
redux-toolkit.js.org
createSlice란 초기 state와 reducer 함수, slice name을 받아서
리듀서와 state에 각각 응답하는 actions creators와 action type을
자동으로 생성해 주는 함수다.
import { createSlice } from "@reduxjs/toolkit";
createReducer도 있지만 createSlice가 더 파워풀하다
2) createSlice 호출하기
import { createSlice } from "@reduxjs/toolkit";
const initialState = { counter: 0, showCounter: true };
createSlice()
3) createSlice는 객체를 인자로서 생성한다.
전역상태의 slice를 미리 만들어 놓는다.
서로 관련된 state끼리 slice를 만든다.
(1) name을 입력한다 (state 식별자)
(2) initialState를 입력한다.
(3) reducers를 입력한다.
reducers는 객체 혹은 맵이다.
여기있는 모든 slice는 리듀서를 필요로 한다.
네 개의 if case문이 있기 때문에
네 개의 메서드를 reducers에 추가한다
모든 메서드는 current state를 자동으로 받는다.
이 메서드들은 나중에 리덕스에 의해 호출되고
current state를 받는 것이다.
createSlice({
name: "counter",
initialState: initialState,
reducers: {
increment(state) {},
decrement(state) {},
increase(state) {},
toggleCounter(state) {},
},
});
(실제로는 상태가 변경되지 않는다)
예를 들어 다음과 같은 코드를 쓸 수 있다.
createSlice({
name: "counter",
initialState: initialState,
reducers: {
increment(state) {
state.counter++;
},
이전에(redux toolkit과 createSlice이 없이)는 이런 코드를 작성하면 안됐다.
작성해도 되게 보일 뿐이었다.
redux toolkit과 createSlice를 사용하면 기존 state를 바꿀 수 없다.
* 왜냐하면 redux toolkit은 내부적으로 immer라는 다른 패키지를 사용하는데
그리고 새로운 state object를 생성하고 모든 state를 변경할 수 없게 유지하고,
우리가 변경한 state는 변하지 않도록 오버라이드 해 준다.
그러면 우리는 불변성을 신경쓰지 않고 변경할 state만 변경해주면
immer가 알아서 변하지 않도록 오버라이드 해준다.
(5) 다른 메서드 안에도 코드를 작성해준다.
그런데 increase 메서드 안에는 페이로드, 즉 추가 데이터가 필요하다.
redux toolkit을 사용해도 액션을 listen하는
reducer 함수를 가질 수 있다.
액션은 엑스트라 페이로드가 들어있다.
createSlice({
name: "counter",
initialState: initialState,
reducers: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
increase(state, action) {
state.counter = state.counter + action.amount;
},
toggleCounter(state) {
state.showCounter = !state.showCounter;
},
},
});
이렇게 작성해서 state를 변경하는 코드처럼 보이지만
사실은 immer덕분에 state를 변경하지 않을 수 있다.
4. 리덕스 툴킷 state 연결하기
1) Slice를 사용하려면 createSlice를 호출해서
return value를 사용해야 한다.
const counterSlice = createSlice({
2) counterSlice를 store에 등록해 준다.
const store = createStore(counterSlice.reducer);
이렇게 하면 slice에서 설정한 리듀서에 접근할 수 있다.
문제 : 만약 state slice가 많아지면서 앱의 규모가 커졌을 때,
문제가 생길 수도 있다.
createStore에는 하나의 리듀서만 전달해야 하는데,
slice가 여러개라면 .reducer를 이용해
서로다른 slice에 접근하는 리듀서도 여러개이기 때문이다.
해결 : redux에는 combineReducers가 있다.
그런데 여기서 리덕스를 사용하지 않고
@reduxjs/toolkit에서 다른 함수를 가져올 수 있다.
configureStore 함수다.
import { createSlice, configureStore } from "@reduxjs/toolkit";
configureStore는 createStore처럼 store를 만든다.
다른점은 여러 개의 리듀서를 하나의 리듀서로 쉽게 합칠 수 있다는 것이다.
configureStore에는 객체를 전달한다.
설정 객체다.
여기서 리듀서 프로퍼티를 정한다.
createStore과 configureStore 무얼 사용하든
리덕스에는 전역상태를 담당하는
단 하나의 주요 리듀서 함수만 있어야 한다.
configureStore에서는 리듀서 값이 단일 리듀서가 될 수 있다.
예를 들어 아래와 같이
const store = configureStore({
reducer: counterSlice.reducer,
});
모든 리듀서 메서드를 가지고 있는
counterSlice의 리듀서를 사용할 수 있다.
이걸 전역 상태를 담당하는 주요 리듀서로서 사용할 수 있다.
큰 규모의 애플리케이션에서 여러개 state slice가 있다면
지금의 리듀서 key에 대한 value 대신
객체를 설정해 그 객체 안에
원하는대로 속성 key 값을 설정해서
(지금 아래 코드에서는 counter)
프로퍼티의 값이 또다른 리듀서 함수가 되도록 한다.
그렇게 리듀서 맵을 생성하면 된다.
그러면 이 맵은 주요 리듀서의 값이 되고,
뒤에서 configureStore이 모든 리듀서를
하나의 큰 리듀서로 병합할 것이다.
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
5. createSlice로 액션을 전달해보기
지금은 if문이 없기 때문에
각 액션에 어떤 식별자가 대응하는지 모른다.
createSlice로 액션을 전달할 수 있다.
createSlice는 서로다른 리듀서에 해당하는
고유 액션 식별자를 자동으로 생성한다.
이 식별자 값을 얻으려면
counterSlice.actions를 사용하면 된다
actions는 key로 가득찬 객체다.
key는 createSlice함수의 리듀서 영역에 있는
메서드 이름과 매칭되어 있다.
그러면 reducer메서드에 접근할 필요가 없다.
대신 redux toolkit에 의해
자동으로 생성된 메서드가 생기고
그 메서드가 호출되면 액션객체가 생성될 것이다.
(~.actions.~ 이 메서드를 action creator라고 불린다)
counterSlice.actions.toggleCounter()
이 객체는 이미 액션마다 다른 고유 식별자와 함께
type프로퍼티를 가지고 있다.
그러므로 액션 객체를 직접 생성할 필요가 없다.
createSlice의 actions key 및 객체를 사용하면 된다.
파일 맨 밑에서
export const counterActions = counterSlice.actions;
action creator 메서드를 counterActions에 할당하고 export하면
액션이 필요한 컴포넌트에 가서 import할 수 있고
counterActions에 접근할 수 있게 된다.
예를들어 increment 메서드에 접근하려고 한다면 아래와 같이 작성하면 된다.
import { useSelector, useDispatch } from "react-redux";
import { counterActions } from "../store/index";
import classes from "./Counter.module.css";
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector(state => state.counter);
const show = useSelector(state => state.showCounter);
const incrementHandler = () => {
dispatch(counterActions.increment());
};
const increaseHandler = () => {
dispatch(counterActions.increase(5));
};
const decrementHandler = () => {
dispatch(counterActions.decrement());
};
const toggleCounterHandler = () => {
dispatch(counterActions.toggleCounter());
};
increase에는 페이로드를 전달해 주는데
이것을 어떻게 추출할 것인가 하는 문제가 남는다
create Slice에 의해 생성된 액션 객체를 잠깐 살펴보면
{type: SOME_UNIQUE_IDENTIFIER, payload: 5}
이런 식으로 생성될 것이다.
payload는 리덕스 툴킷이 사용하는 기본값이다.
그러면
index.js 파일에서 아래와 같이 payload로 접근하면 된다.
increase(state, action) {
state.counter = state.counter + action.payload;
},
redux toolkit을 사용해 보았다.
'공부기록 > [강의노트] Udemy React 완벽가이드 201~300' 카테고리의 다른 글
# 257 [udemy React 완벽 가이드 노트] store 코드 분할해보기 (0) | 2022.10.14 |
---|---|
# 255 [udemy React 완벽 가이드 노트] Redux toolkit에서 여러개의 reducer 사용해보기 (0) | 2022.10.14 |
# 249 [udemy React 완벽 가이드 노트] 토글 카운터 버튼 활성화 (중요: 절대 기존의 state를 변형하지 말것 ) (0) | 2022.10.13 |
# 248 [udemy React 완벽 가이드 노트] action에 페이로드(추가속성) 연결하기 (0) | 2022.10.12 |
# 247 [udemy React 완벽 가이드 노트] 클래스 기반 컴포넌트가 있는 리덕스 (0) | 2022.10.12 |