위의 단점을 redux toolkit이 보완해준다.
: redux toolkit은 더 간결하고 효율적으로 redux를 적용하기 위해 사용하는 redux 도구의 모음이고 아래와 같은 이점이 있다.
: 이전 포스팅에서 작성했던 redux를 redux toolkit에 맞게 리팩토링하였다.
import {createSlice} from '@reduxjs/toolkit';
const initialState = {counter: 0};
// createSlice
// 액션을 전달하는 역할.
const counterSlice = createSlice({
name: 'counter',
// name은 각 slice의 식별자이며 겹치지 않게 작성,
initialState,
reducers: {
// 메서드들은 redux에 의해 호출되고 현재 상태를 받음.
// 서로 다른 리듀서를 구별해놓고 각각 맞는 액션을 발생시킴.
increment(state) {
state.counter++;
},
// 기존 상태를 변경하는 것 같지만 redux/tookit은 immer라는 패키지를 사용해서 기존 state를 변경시키는 코드를 감지하고 자동으로 오버라이딩하도록 도와줌.
decrement(state) {
state.counter--;
},
increase(state, action) {
// 단순히 상태를 반환하는 액션이 아닌, 특정한 값을 받는 action의 경우,
// action.payload로 받을 수 있다(payload 고정)
state.counter = state.counter + action.payload;
},
},
});
// UI컴포넌트에서 사용하기 위해 slice actions 객체 export
export const counterActions = counterSlice.actions;
export default counterSlice;
import {configureStore} from '@reduxjs/toolkit';
// 상태 slice가 많아져서 규모가 커지면 combineReducers를 통해 합칠 수 있지만,
// configureStore를 사용해서 더 쉽게 구현할 수 있음.
import counterSlice from '../reducers/counter';
import showContent from '../reducers/showContent';
import authSlice from '../reducers/auth';
// 설정 객체에서 리듀서 property를 정함.
// reducer의 값이 단일 리듀서가 될 수 있음. // reducer:counterSlice.reducer
const store = configureStore({
reducer: {counter: counterSlice.reducer, showContent: showContent.reducer, auth: authSlice.reducer},
// confugureStore가 모든 리듀서를 큰 하나의 리듀서로 합병해줌.
});
export default store;
import {counterActions, showContentActions} from '../reducers/index';
import {useSelector, useDispatch} from 'react-redux';
const Counter = () => {
const dispatch = useDispatch();
// useSelector를 이용하여 리덕스가 자동으로 subscription을 설정해줌.
// 데이터에 직접적인 변경을 가하면 안되지만 형태의 가공은 가능하다. state.showContent.slice(0,1)
const {counter} = useSelector((state) => state.counter);
const {show} = useSelector((state) => state.showContent);
const incremnetHandler = () => {
dispatch(counterActions.increment());
};
const increaseHandler = () => {
dispatch(counterActions.increase(5));
// 자동으로 액션 생성자를 생성해서 type을 전달하고,
// 작성한 인자를 payload(redux toolkit default)에 저장함.
};
const decremnetHandler = () => {
dispatch(counterActions.decrement());
};
const toggleCounterHandler = () => {
show ? dispatch(showContentActions.hide()) : dispatch(showContentActions.show());
};
return (
<main className={classes.counter}>
<h1>Redux Counter</h1>
{show && <div className={classes.value}>{counter}</div>}
<div>
<button onClick={incremnetHandler}>Increment</button>
<button onClick={increaseHandler}>Increment BY 5</button>
<button onClick={decremnetHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;