React 狀態管理大亂鬥

#react #state management #zustand #jotai #xstate
React 狀態管理大亂鬥
五倍技術部
技術文章
React 狀態管理大亂鬥

React 最讓開發者喜愛的部分之一,就是它的生態系非常的豐富,有許多的第三方套件可以選擇。每一年都會有許多的新技術出現,其中有一個非常有趣的榜單,是 JavaScript Rising Stars,這是一個統計 GitHub 上 JavaScript 相關專案的星星數成長最多的榜單,榜單中細分了很多項目,其中有一個 State Management,這篇文章讓我們來探討與比較一下,這些熱門的 React State Management 有什麼差異。

什麼是 State Management

狀態管理(State Management)在現代前端開發中扮演著核心角色,其對於構建互動式、響應快速的用戶界面至關重要。狀態,簡單來說,是指開發的應用程式在某一時刻的狀況,包括用戶界面的各種資料和設置。例如,一個網頁應用的狀態可能包括用戶的登錄狀態、用戶輸入的數據、服務器的響應數據等。

隨著單頁應用(SPA)的興起和前端技術的迅猛發展,前端應用變得越來越複雜,並且需要管理更多的狀態。在這樣的背景下,有效的狀態管理變得尤為重要,因為:

  • 提升用戶體驗:良好的狀態管理可以確保應用的響應性和穩定性,從而提供流暢的用戶體驗。

  • 便於狀態同步和通信:在複雜的應用中,不同 component 之間可能需要共享和同步狀態。有效的狀態管理可以使這一過程更加清晰和高效。

  • 增強可維護性和可擴展性:當應用的規模不斷擴大,合理的狀態管理方案可以使程式碼保持組織性和可維護性,方便未來的發展和擴展。

  • 便於調試和測試:清晰的狀態管理結構可以讓開發者更容易地追蹤和 debug 應用的行為,同時也有利於寫出更有效的測試案例。

隨著 React、Vue、Angular 等現代前端框架的普及,市面上出現了多種狀態管理解決方案,如 Redux、Vuex、NgRx 等,這些工具旨在幫助開發者更有效地管理狀態,並將狀態的變化與用戶界面的更新緊密連接。選擇合適的狀態管理策略,不僅可以提高開發效率,還能幫助應對日益增加的前端開發挑戰。

在 2023 年的 JavaScript Rising Stars 調查報告中,其中 State Management 前三名分別是:

  • Zustand
  • Jotai
  • XState

接下來我們來看看這三個 State Management 的特色和使用方式。

Zustand

Zustand 是一個為 React 設計的狀態管理庫。它以簡單、輕量級和易於使用而聞名。Zustand 的核心理念是提供一種無需 Redux 那樣繁瑣的設置和模板的狀態管理方法。這使得 Zustand 在 React 開發社群中迅速獲得了人氣,特別是對於那些尋求更簡潔、更直觀狀態管理方案的開發者來說。

如何使用 Zustand

  1. 建立 Store

Zustand 的核心是創建一個 store,這個 store 是一個保存應用狀態的地方。使用 Zustand,你可以通過一個簡單的 function 來建立 store。這個 function 最後會 return 應用的狀態和更新這些狀態。

首先,你需要創建一個 store 來保存應用的狀態。要先引入 create 方法從 Zustand 並使用它來定義你的狀態和更新這些狀態的方法。

import { create } from 'zustand'

const useStore = create((set) => ({
  count: 0, // 初始狀態
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 }))
  // 更新狀態的方法
}))

export default useStore

在這個例子中,useStore 是一個 custom hook,它管理著一個狀態物件,其中包含一個 count 狀態和兩個方法(increase 和 decrease)來更新這個狀態。

  1. 使用 Store

在要使用狀態的 component 中,你可以使用 useStore 來獲取狀態和更新狀態的方法。

import useStore from './zustandStore'

function App() {
  const { count, increase, decrease } = useStore()

  return (
    <div>
      <p>{count}</p>
      <button onClick={increase}>+</button>
      <button onClick={decrease}>-</button>
    </div>
  )
}

我們從 useStore 中提取了 count 狀態以及 increasedecrease 兩個方法。點擊按鈕時會調用這些方法,進而更新 count 的值。當 count 的值改變時,component 會自動重新渲染最新的狀態。

Jotai

Jotai 的核心概念是原子(atoms)。在 Jotai 中,一個原子代表了應用中的一個獨立狀態片段。這些原子可以在整個應用中被讀取和更新,並且它們是彼此獨立的。這種方法使得狀態管理變得非常直觀和模塊化,允許開發者更細緻地控制應用中的各個狀態片段。

如何使用 Jotai

使用 Jotai 主要的重點在建立原子並在 React component 中使用這些原子。

  1. 建立原子

首先,你需要創建一個或多個原子來儲存應用的狀態。每個原子都是一個獨立的狀態單位。

import { atom } from 'jotai';

const countAtom = atom(0); // 一個簡單的原子,初始值為0

export default countAtom;

在這個例子中,我們建立了一個名為 countAtom 的原子,它的初始值為 0。

  1. 使用原子

在 component 中使用原子,使用 useAtom hook 從原子中讀取和更新狀態。

import { useAtom } from 'jotai'
import countAtom from './jotaiAtom'

function App() {
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount((c) => c + 1)}>+</button>
      <button onClick={() => setCount((c) => c - 1)}>-</button>
    </div>
  )
}

我們通過 useAtom hook 來取得一開始建立的 countAtom 的值和一個更新它的 function。點擊按鈕時,我們使用這個更新 function 來改變 countAtom 的值。

XState

XState 的主要理念是使用有限狀態機(Finite State Machines)和狀態圖(Statecharts)來管理應用狀態。它讓開發者以一種視覺化和結構化的方式來定義應用的狀態邏輯,使得狀態管理更加清晰、可預測和可維護。

如何使用 XState

首先,我們先定義一個狀態機:

import { assign, createMachine } from 'xstate';

export const counterMachine = createMachine({
  context: { count: 0 },
  on: {
    inc: {
      actions: assign({
        count: ({ context }) => context.count + 1
      })
    },
    dec: {
      actions: assign({
        count: ({ context }) => context.count - 1
      })
    }
  }
});

在這個例子中,我們定義了一個簡單的狀態機,它有一個 count 狀態,並且可以通過 incdec 兩個事件來改變 count 的值。

接下來,要特別注意的是,在目前的 XState 版本中,本篇文章使用的是 5.5.0 版本,搭配 React 使用還需要 @xstate/react 這個套件。

這個版本使用的方式是 useSelectorcreateActor

import { useSelector } from '@xstate/react'
import { createActor } from "xstate";
import { counterMachine } from './xstate'

const counterActor = createActor(counterMachine).start();

function App() {
  const count = useSelector(counterActor, (state) => state.context.count)

  return (
    <div className='App'>
      <header className='App-header'>
        <h1>Counter</h1>
        <h2>{count}</h2>
        <button onClick={() => counterActor.send({ type: 'inc' })}>+</button>
        <button onClick={() => counterActor.send({ type: 'dec' })}>-</button>
      </header>
    </div>
  )
}

在這個例子中,我們使用 useSelector hook 從 counterActor 中取得 count 狀態。點擊按鈕時,我們使用 counterActorsend 方法來發送 incdec 兩個事件,進而改變 count 的值。

結論

Zustand 提供了一種輕量級、直觀的狀態管理方式,適合那些追求簡潔和高效的 React 開發者。它的主要特點是易於上手,無需繁瑣的設定和模板,使得狀態管理更加靈活和直觀。

Jotai 強調原子化的狀態管理,通過將狀態分解為更小、更獨立的單位(原子),實現了更細緻和模塊化的狀態控制。這種方法不僅提升了狀態管理的可維護性,也增強了組件間狀態的可重用性。

XState 則是以有限狀態機為基礎,提供了一種結構化的狀態管理方法。它適合於需要精細管理狀態轉換和行為的複雜應用,使狀態的變化更可預測和容易理解。

總結一下,選擇哪種狀態管理工具取決於應用的具體需求和開發者的偏好。對於追求簡單快速開發的場景,Zustand 是一個不錯的選擇;對於需要細粒度狀態控制的場景,Jotai 提供了更多的靈活性;而對於複雜的應用狀態邏輯,XState 則能提供強大的結構化管理能力。無論如何,適當的狀態管理策略對於提升應用性能、增強用戶體驗以及保證程式碼可維護性都是非常重要的課題。