[코딩애플] Redux-toolkit
리덕스란?
Redux는 전역으로 상태를 관리할 수 있게 도와주는 라이브러리이다.
이런 라이브러리를 사용하지 않는다면 상위 컴포넌트에서 만든 State가 10개 밑의 deps를 가진 자식 컴포넌트에서 이 state를 전달 받으려면
중간에 끼어 있는 부모들은 그 state를 사용하지 않음에도 계속 드릴처럼 뚫고 내려 가야 하는 단점이 있다.
그런데 Redux는 Store라는 중앙 저장소를 만들어 두고 그곳에서 필요한 곳에 바로 state를 전달할 수 있는 장점이 있다.
리덕스 구 버전과 툴킷이라는 신 버전이 있는데, 신버전을 권장한다.
사용방법
패키지 설치
yarn add @reduxjs/toolkit react-redux
Store.js 파일 만들기
중앙 저장소인 store 파일을 만든다.
// src/store.js
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: { }
})
provider로 전역에 store 내리기
main.jsx 또는 index.js에서 provider를 부모 컴포넌트로 감싸 전역으로 내려준다.
// main.jsx
import { Provider } from "react-redux";
import store from './store.js'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
);
Store에 필요한 state 만들기
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const user = createSlice({
name: 'user',
initialState: 'kim'
})
const stock = createSlice({
name: 'stock',
initialState: [10, 11, 12]
})
const cart = createSlice({
name: 'cart',
initialState: [
{id: 0, name: '장원영', count: 2},
{id: 1, name: '임나연', count: 1}
]
})
export default configureStore({
reducer: {
user: user.reducer
stock: stock.reducer
cart: cart.reducer
}
})
createSlice()에 필요한 state를 만들고,
configureStore()에 전역에서 사용하겠다는 등록을 하면 됨.
createSlice()에서 name은 state의 이름, initialState는 state의 초기값임.
state와 유사해 보이는데 redux에서는 이런 state 형태를 하나의 slice라고 부름.
configureStore()에서 사용 등록을 할 땐 reducer에 객체 형태로, {state명: state의 값}을 적어 주면 된다.
아래 configureStore에서 key와 value는 다음과 같이 구성되어 있다.
보통은 내가 만든 slice 이름과 다른 데서 호출 할 이름과 동일하게 작명한다.
{ 내가다른데서호출할이름 : 여기서만든slice의이름(user).reducer }
다른 컴포넌트에서 state 사용하기
import { useSelector } from 'react-redux';
function App() {
const user = useSelector((state) => state.user);
const stock = useSelector((state) => state.stock);
const cart = useSelector((state) => state.cart);
return (
<>
{state.cart.map((item, index)=>
<tr key={index}>
<td>{state.cart.id}</td>
<td>{state.cart.name}</td>
</tr>
)};
</>
);
}
useSelector훅을 통해 store에 접근 가능하도록 호출하여 state.state명으로 꺼내온다. 그리고 변수에 할당해서 사용하면 된다.
상태 변경 함수 만들기 (reducer)
reducer 만들고 export 하기
// store.js
const user = createSlice({
name : 'userName',
initialState : '원영',
// 상태 변경 함수 작성
reducers : {
changeUserName(state) {
return '장' + state
},
// 여러 개 작성 가능
}
})
// 만든 상태 변경 함수 내보내야 함.
export let { changeName, 함수2, 함수3, ... } = user.actions;
// actions에는 Reducer가 모두 호출된다.
상태 변경 함수(reducer)는 여러 개 만들어도 된다. 콤마를 찍어서 분리만 해주면 된다. state를 매개 변수로 받으면 현재 slice(상태)의 initialState(초기값)을 함수 내에서 사용할 수 있다.
함수에서 return 값을 하는 형태로 slice의 initialState 값을 변경해줄 수 있다.
만든 함수 사용하기
// App.jsx
// reducer 함수 import 하기
import { changeUserName } form './../store.js';
function App (
// reducer 함수를 실행해주는 dispatch 메서드 사용 선언하기
const dispatch = useDispatch();
return (
<>
{/* dispatch 함수로 감싸서 삿ㅇ태 변경 함수 호출하기 */}
<button onclick={ () => {dispatch(changeUserName())} }>
</>
)
만든 reducer 함수를 사용하는 3 steps.
- 1. 사용할 컴포넌트에서 상태 변경 함수(reducer) store로 부터 import하기
- 2. 사용할 컴포넌트에서 dispatch 사용 선언하기
- 3. 함수를 호출하는 부분에서 dispatch(실행할함수()) 로 감싸서 호출하기
state가 객체, 배열일 경우 상태 변경하는 방법
// store.js
import { createSlice } from '@reduxjs/toolkit'; // 필요한 import 추가
const user = createSlice({
name: 'user',
initialState: {name: '장원영', age: 21},
reducers: {
changeName(state) {
state.name = '안유진'
increase(state) {
state.age += 1
}
})
export const { changeName, increase } = user.actions;
export default user.reducer;
store에 있는 state의 initialState가 원시 자료형일 경우에는 return문을 통해 데이터를 바꿔 주었지만, object, array 타입에서는 return문 없이 직접 수정이 가능하다.
slice를 분리 시키기
위 예제 처럼 store와 slice를 store 한 파일에 작성할 수도 있지만, 프로젝트의 규모가 커지면 가독성이 좋지 않고 유지보수가 어려울 수 있기 때문에 slice가 적더라도 분리해서 관리하는 패턴에 익숙해지는 것이 좋다.
파일트리
src/
├── store/
│ ├── store.js // Redux store 설정 파일
│ ├── userSlice.js // user slice 파일
│ ├── anotherSlice.js // another slice 파일
│ └── ... // 추가적인 slice 파일들
└── ...
slice 파일들
// userSlice.js
import { createSlice } from '@reduxjs/toolkit';
const user = createSlice({
name: 'user',
initialState: { name: '장원영', age: 21 },
reducers: {
changeName(state) {
state.name = '안유진';
},
increase(state) {
state.age += 1;
}
}
});
export const { changeName, increase } = user.actions;
export default user.reducer; // 리듀서 export
// anotherSlice.js
import { createSlice } from '@reduxjs/toolkit';
const another = createSlice({
name: 'another',
initialState: { value: 0 },
reducers: {
increment(state) {
state.value += 1;
}
}
});
export const { increment } = another.actions;
export default another.reducer; // 리듀서 export
store.js 파일
// store.js
import { configureStore, combineReducers } from '@reduxjs/toolkit';
import userReducer from './userSlice'; // user 슬라이스 리듀서 import
import anotherReducer from './anotherSlice'; // 다른 슬라이스 리듀서 import
const rootReducer = combineReducers({
user: userReducer,
another: anotherReducer,
});
const store = configureStore({
reducer: rootReducer,
});
export default store;
store 파일에서는 slice 자체가 아니라 리듀서만 import 한다.
'Programing > React' 카테고리의 다른 글
React-Router-dom Page Routing Quick Start (0) | 2024.06.16 |
---|---|
React Redux Toolkit Quick Start (0) | 2024.06.16 |
zustand 상태 관리 (0) | 2024.06.14 |
로그인 하지 않은 상태에서는 헤더가 렌더링 되지 않게 조건부 렌더링 설정하기 (0) | 2024.06.14 |
TanStack Query 기본 사용법 (0) | 2024.06.14 |
댓글