React에서 Redux Toolkit 사용하기
// npx
npx create-react-app .
// npm
npm init react-app .
// yarn
yarn create react-app .
// npm
npm install @reduxjs/toolkit react-redux
// yarn
yarn add @reduxjs/toolkit react-redux
만약 해당 위치에 이미 redux를 설치한 경우 package.json 파일로 가서 redux dependencies 를 지워줘야 한다.
카운터 값과 더하기 빼기 버튼이 있는 컴포넌트를 만들자. 당연히 지금은 아무 동작도 하지 않는다.
components/Counter.js
const Counter = () => {
const counter = 0;
return (
<div>
<h2>{counter}</h2>
<div>
<button>더하기</button>
<button>빼기</button>
</div>
</div>
);
};
const store = configureStore({
reducer: {리듀서 map},
});
store는 위와 같이 configureStore
를 사용해서 만들 수 있다.
Redux Toolkit를 사용하는 경우도 리액트 앱 하나에 하나의 store만 존재해야 한다.
store/index.js
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: {},
});
export default store;
여기서 reducer는 별도의 슬라이스를 만들어서 구현할 수 있다. 일단은 빈 객체로 두자.
const slice = createSlice({
name: slice이름,
initialState: state초기값,
reducers: {
// 리듀서구현
},
});
슬라이스는 store의 조각이라고 생각하면 된다. 위와 같이 createSlice
를 사용해서 만들 수 있다. 여러 슬라이스는 configureStore
를 통해 하나의 store에 저장된다.
Redux Toolkit를 사용하지 않고 Redux 만을 사용해서 리듀서를 구현했을 때는 기존 state를 직접적으로 변경해서는 안 되고 새로운 객체로 반환해야 했다. 하지만 Redux Toolkit를 사용하면 리듀서 내부에 state를 직접 변경하는 코드를 작성해도 된다. (state.counter++;
사용 가능) 이는 Redux Toolkit 내부적으로 새로운 객체를 만들어서 반환하기 때문에 가능한 것이다.
store/counter.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
counter: 0,
}
export const counterSlice = create({
name: 'counter',
initialState,
reducers: {
add: (state, action) => {
state.counter += action.payload;
},
sub: (state, action) => {
state.counter -= action.payload;
},
}
});
export const counterActions = counterSlice.actions;
export default couterSlice.reducer;
state.counter
값을 직접적으로 바꿀 수 있다.action.payload
는 counterSlice
의 actions 을 dispatch 할 때 넘기는 인수를 말한다.아까 비워두었던 store
의 reducer
에 방금 counterSlice
에서 정의한 리듀서 함수를 등록하자.
store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counter';
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
counterSlice.reducer
를 default로 export 했기 때문에 여기서 counterReducer
는 store/counter.js 의 counterSlice.reducer
가 된다.const state = useSelector(state => state.슬라이스key.해당슬라이스의state);
Redux toolkit도 useSelector
를 사용해서 store의 특정 state에 접근할 수 있다. 콜백 함수의 반환값에 접근하는 것이다.
component/Counter.js
import { useSelector } from 'react-redux';
const Counter = () => {
const counter = useSelector(state => state.counter.counter);
return (
<div>
<h2>{counter}</h2>
<div>
<button>더하기</button>
<button>빼기</button>
</div>
</div>
);
};
useSelector
의 콜백함수를 통해 state.counter
는 counterReducer
에 접근하고, state.counter.counter
는 counterSlice
의 state 중 counter
를 가져온다.const dispatch = useDispatch();
dispatch(액션.리듀서함수(payload));
Redux toolkit도 역시 useDispatch
를 사용해서 store의 특정 action에 접근할 수 있다. 여기서 리듀서함수의 인자는 action.payload
로 접근한다.
component/Counter.js
import { useSelector, useDispatch } from 'react-redux';
import { counterActions } from '../store/counter';
const Counter = () => {
const counter = useSelector(state => state.counter.counter);
const dispatch = useDispatch();
const addHandler = () => {
dispatch(counterActions.add(10));
};
const subHandler = () => {
dispatch(counterActions.sub(10));
};
return (
<div>
<h2>{counter}</h2>
<div>
<button onClick={addHandler}>더하기</button>
<button onClick={subHandler}>빼기</button>
</div>
</div>
);
};
dispatch(counterActions.add(10))
의 10은 리듀서에서 action.payload
로 접근할 수 있다.<Provider store={store}>
<App />
</Provider>
Redux Toolkit도 동일하게 최상위 컴포넌트를 Provider 로 감싸서 store를 제공해야 한다. 이렇게 감싸면 내부 컴포넌트는 리덕스의 store를 전역적으로 사용할 수 있다.
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);