2024. 1. 4. 02:37ㆍFront-end/React.js
Background
React 공식 문서에 따르면 상태(state)를 단일 컴포넌트에서 사용하는 정도로 앱이 단순할때는 굳이 상태관리 라이브러리를 사용하지 않아도 됩니다.
그러나 부모와 자식 컴포넌트 등의 여러 컴포넌트에서 동일한 상태에 접근하고 업데이트하고 동시에 여러 UI에 보여줘야 한다면 상태관리 라이브러리를 사용해야 합니다. 그렇지 않으면 props drilling등으로 상태를 계속 하위 컴포넌트로 전달해주는 등 비효율적이기 때문입니다.
Redux
상태관리 라이브러리에는 Redux, Recoil, Zustand, React Query 등이 있습니다. 라이브러리의 우열을 따지기보다는 각자의 프로젝트에 맞는 라이브러리를 사용하는게 좋습니다. 이 글에서 설명하는 Redux는 다음과 같은 특징이 있습니다.
- 큰 프로젝트의 상태관리에 적합합니다.
- 상태를 디버깅하는 툴이 있습니다.
- 비동기 처리를 도와주는 Redux-thunk, Redux-saga 등을 미들웨어에 조합하여 사용할 수 있습니다.
- action, dispatch, store, reducer로 이어지는 단방향 데이터 흐름으로 예측가능한 코드를 작성할 수 있습니다.
- 그러나 보일러 플레이트 코드가 많이 발생하기 때문에 코드 작성 시 제한사항이 많은 편입니다.
Redux 공식문서에 있는 사진입니다. Redux의 원리를 가장 쉽게 표현해준다고 생각해서 가져왔습니다
1. UI에서 이벤트가 발생하면
2 Action을 Dispatch합니다.
3. 이 Action을 Store에서 받게 되면
4. Store 내부의 Reducer는 State를 업데이트하고 반환합니다.
- 이 때, Reducer는 Side Effect가 발생하지 않게 기존의 상태를 복사해서 복사본에 상태를 업데이트합니다.
5. 업데이트된 상태를 기반으로 리렌더링합니다.
Redux-toolkit
Redux의 흐름을 대강 알고 있는 상태라면, Action과 Store, Reducer 등의 개념이 꽤 복잡하게 느껴지실겁니다. 여기에 미들웨어를 추가로 설치하고 조합해야하는 상황까지 더해지면 매우 복잡해집니다. 따라서 이를 단순화하고자 Redux-toolkit이 출시되었습니다.
* React.js에 TypeScript환경 기준으로 redux-toolkit을 설명합니다.
1. redux, react-redux, redux-toolkit 설치하기
npm install redux react-redux @reduxjs/toolkit
2. React로 + 버튼을 누르면 숫자가 증가, - 버튼을 누르면 숫자가 감소하는 카운터 앱을 만들려고 합니다.
3. 원활한 유지보수를 위해서 상태관리 코드를 별도의 파일로 관리하는것이 일반적입니다.
store/index.ts : 기존 Redux에서는 Action과 Reducer 파일을 따로 만들었으나 Redux-toolkit은 slice 단위로 Reducer와 Action을 함께 관리합니다.
import { createSlice } from "@reduxjs/toolkit";
export const counterSlice = createSlice({
name: "counter",
initialState: {
value: 0,
},
reducers: {
increase: (state) => {
state.value += 1;
},
decrease: (state) => {
state.value -= 1;
},
},
});
export const counterActions = counterSlice.actions;
createSlice: slice를 만듭니다.
name: 이름을 설정합니다.
initialState: 초기값을 설정합니다.
reducers: 상태를 어떻게 업데이트할 지 정의합니다.
카운터 앱이니 + 버튼을 누르면 상태가 +1, - 버튼을 누르면 상태가 -1 업데이트 되어야 합니다.
counterSlice의 action을 counterActions으로 따로 저장할 수 있습니다. 코드를 작성 후 counterSlice와 counterAction을 export합니다.
store/store.ts : 상태를 저장하고 여러 Reducer를 핸들링합니다. 추후 미들웨어를 조합할 수도 있습니다.
import { configureStore } from "@reduxjs/toolkit";
import { counterSlice } from ".";
const store = configureStore({
reducer: { counter: counterSlice.reducer },
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
configureStore: 여러 Reducer를 모아서 store에 저장합니다.
RootState: TypeScript에서 state의 타입을 지정하기 위해 선언합니다.
코드를 작성 후 store와 RootState를 export합니다.
4. 카운터의 상태를 업데이트하는 코드를 작성합니다.
import { useDispatch } from "react-redux";
import { counterActions } from "../../store";
export default function CounterButtonContainer() {
const dispatch = useDispatch();
return (
<>
<button
onClick={() => {
dispatch(counterActions.increase());
}}
>
+
</button>
<button
onClick={() => {
dispatch(counterActions.decrease());
}}
>
-
</button>
</>
);
}
useDispatch: Action을 전달하여 상태 업데이트를 요청할 수 있는 Hook입니다.
counterActions: store/index.ts에서 export한 Action입니다. increase, decrease 2종류가 있습니다.
상태를 직접 조작하여 업데이트하지 않고 Dispatch를 거쳐서 Action을 Store에 전달하는것이 Redux의 특징입니다.
5. 카운터의 상태를 보여주는 코드를 추가합니다.
...
import { RootState } from "../store/store";
export default function CounterButtonContainer() {
...
const count = useSelector((state: RootState) => state.counter.value);
return (
<>
...
<div>
<text>개수: {count}개</text>
</div>
...
</>
);
}
useSelector: 상태를 가져올 수 있습니다.
RootState: 상태의 타입을 지정하기 위해 앞서 선언한 store/store.ts에서 가져옵니다.
6. 앱을 실행하고 버튼을 이리저리 눌러봅니다.
7. 상태를 더 자세히 디버깅하려면 크롬 익스텐션을 추가합니다.
https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ko
'Front-end > React.js' 카테고리의 다른 글
React Query 라이브러리의 사용법 및 특징: 서버 상태 관리 (0) | 2024.01.18 |
---|---|
React를 프로젝트와 컴포넌트 단위에서 설계하기 (0) | 2023.12.28 |
[React] 컴포넌트 내부에서 CSS를 쉽게 스타일링 하기: Emotion (0) | 2023.05.12 |
[React] React 앱을 배포하기: Netlify (0) | 2023.01.31 |
[React] 웹 페이지에 차트 만들기: React-Google-Charts (0) | 2022.09.28 |