티스토리 뷰
Zustand
- reduxjs/toolkit 이 많이 편해지긴 했지만, 여전히 다루기 거대하고 복잡하다
포스팅 게제 현시점 (2024.12.24) zustand의 인기와 사용량이 상당히 증가하였다
- 1위가 reduxjs/toolkit 인 것은 여전하다, 그렇지만 zustand가 거의 동일한 수준으로 인지도가 높아졌다
- jotai 는 3순위 정도 되며, 4순위 recoil 과, 5순위 valtio(어려워 보인다...) 는 상대적으로 1, 2 순위와 비교하였을 때
그 사용량이 매우 저조하다
- zutand는 Redux와 매우 닮아 있으며, 간단하게는 메서드 방식과 프로젝트 규모와 소스코드가 길어지는 경우
redux처럼 리듀서 방식으로 사용할 수 있다.
zustand 의 메서드 방식
장점
- 간단함: 불필요한 액션 타입이나 리듀서를 정의하지 않아도 되므로 코드가 간결하고 직관적임.
- 빠른 구현: 단순한 상태 관리에서는 빠르게 구현 가능.
- 가독성: 함수 이름(increment, decrement)이 명확하여 상태를 변경하는 로직이 직관적임.
단점
- 확장성 부족: 상태와 액션이 많아질 경우, 모든 로직을 한 파일에 유지해야 하므로 관리가 어려워질 수 있음.
- 테스트 어려움: 각 함수의 로직을 독립적으로 테스트하기 힘듦(리듀서 방식보다 상대적으로).
사용 사례
- 상태가 단순하고 액션이 많지 않은 소규모 프로젝트에서 적합.
- 간단한 상태 업데이트가 주된 요구사항일 때 선호.
src/stores/methodCountStore.ts
import { create } from "zustand";
type State = {
count: number;
};
type Actions = {
increment: (qty: number) => void;
decrement: (qty: number) => void;
};
export const useMethodCountStore = create<State & Actions>((set) => ({
count: 0,
increment: (qty: number) => set((state) => ({ count: state.count + qty })),
decrement: (qty: number) => set((state) => ({ count: state.count - qty })),
}));
src/components/MethodCounter.tsx
import React from "react";
import { useMethodCountStore } from "../stores/methodCountStore";
const MethodCounter = () => {
const { count, increment, decrement } = useMethodCountStore();
return (
<div>
<h1>Method Count: {count}</h1>
<button onClick={() => increment(1)}>+1</button>
<button onClick={() => decrement(1)}>-1</button>
</div>
);
};
export default MethodCounter;
src/App.tsx
import "./styles.css";
import MethodCounter from "./components/MethodCounter";
export default function App() {
return (
<div className="App">
<MethodCounter />
</div>
);
}
zustand 의 리듀서 방식
장점
- 유사성: Redux와 같은 리듀서 기반 상태 관리 방식과 유사하므로 Redux 경험이 있는 개발자들이 쉽게 이해하고 적응할 수 있음.
- 확장성: 액션이 많아질 경우, 리듀서를 별도 파일로 분리하여 상태 관리와 비즈니스 로직을 모듈화할 수 있음.
- 테스트 용이성: 리듀서 로직을 독립적으로 테스트하기 쉬움.
단점
- 간단한 상태 관리에 불필요한 복잡성: 리듀서 함수와 액션 타입을 정의해야 하므로 초기 설정이 비교적 번거로움.
- 가독성 저하: 코드의 길이가 길어지고, 디스패치를 사용하는 방식이 직관적이지 않을 수 있음.
사용 사례
- 상태가 복잡하고 액션이 많은 대규모 프로젝트에서 적합.
- 상태 관리 로직이 단순하지 않은 경우(다양한 액션 타입과 비즈니스 로직이 필요한 경우) 선호.
src/stores/countStore.ts
import { create } from "zustand";
type State = {
count: number;
};
type Actions = {
increment: (qty: number) => void;
decrement: (qty: number) => void;
};
type Action = {
type: keyof Actions;
qty: number;
};
type Dispatch = {
dispatch: (action: Action) => void;
};
const countReducer = (state: State, action: Action): State => {
switch (action.type) {
case "increment":
return { count: state.count + action.qty };
case "decrement":
return { count: state.count - action.qty };
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
};
export const useCountStore = create<State & Dispatch>((set) => ({
count: 0,
dispatch: (action: Action) => set((state) => countReducer(state, action)),
}));
src/components/Counter.tsx
import React from "react";
import { useCountStore } from "../stores/countStore";
const Counter = () => {
const { count, dispatch } = useCountStore();
const handleIncrement = () => {
dispatch({ type: "increment", qty: 1 });
};
const handleDecrement = () => {
dispatch({ type: "decrement", qty: 1 });
};
return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleIncrement}>+1</button>
<button onClick={handleDecrement}>-1</button>
</div>
);
};
export default Counter;
src/App.tsx
import "./styles.css";
import Counter from "./components/Counter";
export default function App() {
return (
<div className="App">
<Counter />
</div>
);
}
결론
- 초기 상태가 단순하고 액션이 몇 개 없다면, 메서드 방식을 사용
- 복잡한 상태 관리나 상태 변경 로직이 많아질 경우, 리듀서 방식으로 전환하는 것이 좋을듯
- 프로젝트 초기에는 간단한 방식으로 시작하고, 복잡성이 증가하면 리듀서 방식으로 리팩터링하는 것도 좋은 접근일 듯 하다
위의 예제 실제 코드 보기
'■ 프론트엔드 ■ > React' 카테고리의 다른 글
react using state when you don't need it (0) | 2024.03.29 |
---|---|
React Hook Form: FormProvider-useFormContext (0) | 2024.03.29 |
React Hook Form (useState-less 패턴) (0) | 2024.03.29 |
re-resizeable 을 이용한 오더북 개수조정 컴포넌트 (1) | 2024.02.09 |
yarn berry error - `node:internal/process/esm_loader:40` `internalBinding('errors').triggerUncaughtException` (0) | 2023.12.13 |
댓글