[Redux] 리덕스 툴킷 사용하기

리덕스 툴킷 무엇일까?
리덕스 툴킷은 리덕스를 좀 더 효율적으로 사용할 수 있게 만들어주는, 말 그대로의 도구 모음이다.
리덕스 툴킷을 사용하면 매번 상태 복사를 하지 않고도 불변성을 지키며 상태 업데이트를 할 수 있고,
상태를 여러 조각으로 만들어서 필요한 부분만 업데이트하고 사용할 수 있다.
이렇게나 편리한 리덕스 툴킷, 사용하러 가보자고!🙌
configureStore
먼저, 리덕스 툴킷에서도 createStore처럼 스토어를 만들어주는 메서드가 있다.
configureStore가 그것인데, configureStore는 createStore와 비슷하지만 다른 점도 있다.
다른 점 중 하나는 configureStore가 여러 상태 조각들을 하나로 모아준다는 것이다.
createSlice
애플리케이션 내에 수많은 상태가 존재할 수 있는데,
어떤 상태는 앱 전체에서 필요하고 어떤 상태는 몇몇 컴포넌트에서만 필요하다.
그렇지만 이 상태들은 전부 스토어라는 하나에 공간에만 보관할 수 있다.
그렇게 되면 상태를 업데이트할 때마다 업데이트하지 않는 상태들까지도 다 복사해 와서
상태들을 담은 객체에 넣어 줘야 할 것이다. 상당한 비효율이 아닐 수 없다.
그래서 리덕스 툴킷에서는 상태를 쪼개서 저장할 수 있는 상태 쪼개기 기능을 제공한다.
createSlice를 사용하면 상태들의 Slice를 만들 수 있고,
하나의 기능을 구현하는 데 필요한 상태들을 묶어서 슬라이스를 만들면 업데이트가 아주 편리해진다.
전에 만들었던 카운터 애플리케이션의 예시를 보자.
const counterReducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return {
counter: state.counter + action.amount,
showCounter: state.showCounter,
};
}
if (action.type === "DECREMENT") {
return {
counter: state.counter - action.amount,
showCounter: state.showCounter,
};
}
if (action.type === "TOGGLE") {
return {
counter: state.counter,
showCounter: !state.showCounter,
};
}
return state;
};
상태를 업데이트해 주는 reducer 함수다.
고작 상태가 두개밖에 없어서 그렇게 복잡하지는 않지만,
상상력을 발휘해 어마어마하게 큰 애플리케이션을 만들었다고 생각해 보면,
상태 하나를 변경할 때마다 변경하지 않는 상태들까지도 모두 복사해서 리턴할 객체에 담아 줘야 한다.
createSlice를 사용해서 상태를 쪼개고 업데이트하고 사용해 보자.
import { createSlice } from "@reduxjs/toolkit"; //createSlice 임포트
const initialCounterState = { counter: 0, showCounter: true };
const counterSlice = createSlice({
name: "counter",
initialState: initialCounterState,
reducers: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
increase(state, action) {
state.counter = state.counter + action.payload; //payload라는 이름은 디폴트로 지정돼있다
},
toggleCounter(state) {
state.showCounter = !state.showCounter;
},
},
});
export const counterReducer = counterSlice.reducer;
export const counterActions = counterSlice.actions; //reducers가 아니라 actions라는 점을 주의
카운터에 관련한 상태는 카운터라는 하나의 컴포넌트에서 사용하는 것이기 때문에 더 쪼갤 필요는 없다.
그래서 하나의 상태 슬라이스에 담아 주었다.
createSlice는 조각 이름, 상태 초기값, 리듀서 함수들로 이루어진 객체를 받아
그에 맞는 액션 생산자와 액션 타입을 포함하는 리듀서 조각을 자동으로 만들어 준다.
createSlice를 사용하면 액션에 따른 분기를 시킬 때 if문을 활용하지 않고
reducers라는 항목 내에서 함수를 나열하는 식으로 설정하면 된다.
더 좋은 점은 변경하지 않는 상태는 복사해 오지 않아도 되고,
불변성을 지키지 않는 '것처럼' 코드를 작성해도 된다는 것이다.
현재 상태를 가져와 그냥 새로운 상태로 할당해주면 된다.
그래도 리덕스 툴킷 내부적으로 새로운 상태를 선언해서 업데이트를 진행한다.
상태를 여러 개로 쪼개서 각각 다른 파일에 담았다면 합쳐주는 부분도 있어야 한다.
하나의 애플리케이션에는 하나의 스토어만 존재할 수 있으므로 상태를 쪼개도 스토어는 하나다.
import { counterReducer } from "./counter";
import { authReducer } from "./auth";
import { configureStore } from "@reduxjs/toolkit";
const store = configureStore({
reducer: { counter: counterReducer, auth: authReducer },
});
//store는 단 하나이므로 slice를 여러개 만들더라도 하나의 스토어에 저장해야 하고,
//cofigureStore도 한번만 호출해야 한다.
export default store;
auth라는 새로운 상태 조각을 만들어 카운터와는 다른 파일에 담아 줬고,
제3의 파일에서 이 두 상태 조각들을 합쳐줬다.
configureStore가 바로 이 상태들을 합쳐 주는 역할을 한다.
각각의 상태의 리듀서 함수를 객체에 담아서 configureStore로 스토어에게 넘겨 준다.
그러면 상태를 사용하는 컴포넌트로 가서 어떻게 사용하고 있는지 알아보자
import classes from "./Counter.module.css";
import { useSelector, useDispatch } from "react-redux";
import { counterActions } from "../store/counter";
const Counter = () => {
const dispatch = useDispatch(); //디스패치 함수
const counter = useSelector((state) => state.counter.counter); //상태가 담긴 곳
const incrementHandler = () => {
dispatch(counterActions.increment()); //액션 사용
};
const decrementHandler = () => {
dispatch(counterActions.decrement());
};
const increaseHandler = () => {
dispatch(counterActions.increase(5));
};
const counterIsShown = useSelector((state) => state.counter.showCounter);
const toggleCounterHandler = () => {
dispatch(counterActions.toggleCounter());
};
이전과 달라진 점은 useSelector를 사용하는 부분과 액션을 디스패치하는 부분이다.
useSelector를 사용할 때 이제는 스토어에 있는 상태 전체를 가져오는 게 아니라
상태 조각들 중 어떤 부분을 사용할지를 명시해야 한다.
그리고 액션을 디스패치할 때는 타입을 명시할 필요 없이
페이로드가 있는 경우에만 페이로드를 전달인자로 전달해 주면 된다.
리듀서 함수를 만들 때 if문이 아니라 각각의 함수들만 담아줬기 때문이다.
이상으로 리덕스 툴킷을 이용해 상태를 쪼개고 업데이트하고 사용하고
스토어에 합쳐서 담아주는 방법을 배워 봤다. 리덕스 툴킷 너무 편해..!! 사랑혀..!!❤️