iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
Modern Web

React 學得動嗎系列 第 13

[Day 13] React 狀態管理介紹:Redux、MobX 和Zustand

  • 分享至 

  • xImage
  •  

在 React 開發中,隨著應用程式變得愈加複雜,狀態管理也變得更加困難。今天將介紹三種常見的狀態管理工具:ReduxMobXZustand,以協助開發者更有效地管理應用程式的狀態。

為什麼需要狀態管理工具?

當應用程式規模擴大時,組件之間的狀態共享和管理會變得複雜。這時候,需要一個集中管理狀態的工具,來協助我們維護和更新應用程式的狀態,確保資料的一致性和可預測性。

Redux:嚴謹的狀態管理工具

Redux 提供了一個可預測的狀態管理模式,通過嚴格的流程來處理狀態變化。

Redux 的核心概念:

  1. Store:儲存整個應用程式的狀態。
  2. Action:描述發生的事件。
  3. Reducer:根據 Action 更新狀態的純函數。

來看個簡單的例子:

import { createStore } from 'redux';

// Reducer
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
};

// Store
const store = createStore(counterReducer);

// 使用
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // 輸出:1

Redux 的優點是狀態變化非常可預測,但缺點是需要寫不少樣板程式。

MobX:靈活的狀態管理工具

相比之下,MobX 提供了一種反應式的狀態管理方式,允許開發者以更簡潔的程式碼來管理狀態。

MobX 的核心概念:

  1. Observable State:可以被追蹤的狀態。
  2. Computed Values:由狀態衍生出的值。
  3. Reactions:狀態變化時自動執行的動作。

MobX 的例子:

import { makeAutoObservable } from 'mobx';

class CounterStore {
  count = 0;
  
  constructor() {
    makeAutoObservable(this);
  }
  
  increment() {
    this.count++;
  }
  
  decrement() {
    this.count--;
  }
}

const counterStore = new CounterStore();

// 使用
counterStore.increment();
console.log(counterStore.count); // 輸出:1

MobX 的優點是簡單直觀,程式碼數量少,但狀態變化可能不夠明確。

Zustand:輕量級的狀態管理工具

說到現在最受歡迎的狀態管理工具,我們不能不提 ZustandZustand是一個輕巧且靈活的狀態管理工具,結合了 Redux 的可預測性和 MobX 的簡潔性。

Zustand 的特點:

  1. 簡單易用:API 簡潔,學習曲線平緩。
  2. 輕量級:體積小,對專案負擔較低。
  3. 靈活性高:可以輕鬆整合到現有專案中。
  4. TypeScript 支援:提供良好的 TypeScript 相容性。

Zustand 的例子:

import create from 'zustand';

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
}

const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

// 在組件中使用
function Counter() {
  const { count, increment, decrement } = useCounterStore();
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

Zustand 不需要包裹整個應用或進行複雜的配置,即可實現強大的狀態管理。

如何選擇?

  • Redux:適合大型、複雜的應用,需要嚴格的狀態追蹤和豐富的中間件支持。
  • MobX:適合希望程式碼簡潔、狀態管理直觀,並偏好物件導向方式的開發者。
  • Zustand:適合中小型專案,提供輕量級且靈活的解決方案。
  • React 內建工具:對於較小的應用,可以使用 React 的 Context APIuseReducer Hook。

實際應用:購物車

讓我們用一個簡單的購物車例子來對比 Redux、MobX和Zustand :

Redux 版本

// actions.ts
export const addToCart = (item) => ({
  type: 'ADD_TO_CART',
  payload: item
});

// reducer.ts
const initialState = { items: [] };

const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TO_CART':
      return { ...state, items: [...state.items, action.payload] };
    default:
      return state;
  }
};

// Component
import { useDispatch, useSelector } from 'react-redux';
import { addToCart } from './actions';

const ShoppingCart = () => {
  const dispatch = useDispatch();
  const items = useSelector(state => state.items);

  return (
    <div>
      <button onClick={() => dispatch(addToCart({ id: 1, name: '蘋果' }))}>
        加入蘋果
      </button>
      <ul>
        {items.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  );
};

MobX 版本

import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';

class CartStore {
  items = [];

  constructor() {
    makeAutoObservable(this);
  }

  addToCart(item) {
    this.items.push(item);
  }
}

const cartStore = new CartStore();

const ShoppingCart = observer(() => {
  return (
    <div>
      <button onClick={() => cartStore.addToCart({ id: 1, name: '蘋果' })}>
        加入蘋果
      </button>
      <ul>
        {cartStore.items.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  );
});

Zustand 版本

import create from 'zustand';

interface CartItem {
  id: number;
  name: string;
}

interface CartStore {
  items: CartItem[];
  addToCart: (item: CartItem) => void;
}

const useCartStore = create<CartStore>((set) => ({
  items: [],
  addToCart: (item) => set((state) => ({ items: [...state.items, item] })),
}));

const ShoppingCart = () => {
  const { items, addToCart } = useCartStore();

  return (
    <div>
      <button onClick={() => addToCart({ id: 1, name: '蘋果' })}>
        加入蘋果
      </button>
      <ul>
        {items.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  );
};

可以看到,Zustand 的實現方式非常簡潔,而且不需要額外的 Provider 包裹。

小結

今天我們學習了 React 中三個主要的狀態管理工具:Redux、MobX 和 Zustand。它們各有特色,幫助我們管理複雜的狀態。

選擇狀態管理工具要根據專案需求。有時候,使用 React 內建的狀態管理功能就足夠了;但當專案變得複雜時,這些工具就能派上用場。而在現代 React 開發中,Zustand 因其簡潔和靈活性,越來越成為專案首選。

如果你想更深入地了解這些工具,可以查看它們的官方文件:


上一篇
[Day 12] React 寫測試的實用指南
下一篇
[Day 14] React 生態系:React Query 和 React Hook Form
系列文
React 學得動嗎30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言