深入理解 React 的 useSyncExternalStore Hook

自足發表於2024-07-16

深入理解 React 的 useSyncExternalStore Hook

大家好,今天我們來聊聊 React 18 引入的一個新 Hook:useSyncExternalStore。這個 Hook 主要用於與外部儲存同步狀態,特別是在需要確保狀態一致性的場景下非常有用。本文將深入探討這個 Hook 的使用場景、工作原理,並透過程式碼示例來幫助大家更好地理解。

為什麼需要 useSyncExternalStore?

在 React 18 之前,我們通常使用 useEffect 或者 useLayoutEffect 來訂閱外部儲存的變化。然而,這些方法有時會導致狀態不一致的問題,特別是在併發模式下。useSyncExternalStore 旨在解決這些問題,確保狀態在任何時候都是一致的。

基本用法

首先,我們來看一下 useSyncExternalStore 的基本用法。這個 Hook 接受三個引數:

  1. subscribe: 一個函式,用於訂閱外部儲存的變化。
  2. getSnapshot: 一個函式,用於獲取當前的儲存快照。
  3. getServerSnapshot: 一個函式,用於在伺服器端渲染時獲取儲存快照(可選)。
import React, { useSyncExternalStore } from "react";

// 模擬一個外部儲存
const store = {
  state: 0,
  listeners: new Set(),
  subscribe(listener) {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  },
  setState(newState) {
    this.state = newState;
    this.listeners.forEach((listener) => listener());
  },
  getState() {
    return this.state;
  },
};

function useStore() {
  return useSyncExternalStore(
    store.subscribe.bind(store),
    store.getState.bind(store)
  );
}

function Counter() {
  const state = useStore();
  return (
    <div>
      <p>Count: {state}</p>
      <button onClick={() => store.setState(state + 1)}>Increment</button>
    </div>
  );
}

export default Counter;

在這個示例中,我們建立了一個簡單的計數器應用。store 是一個模擬的外部儲存,包含狀態和訂閱邏輯。useStore 是一個自定義 Hook,使用 useSyncExternalStore 來訂閱儲存的變化並獲取當前狀態。

深入理解

useSyncExternalStore 的核心在於它如何確保狀態一致性。它透過同步的方式獲取儲存快照,避免了非同步更新帶來的潛在問題。在併發模式下,React 可能會在渲染過程中多次呼叫 getSnapshot,以確保狀態的一致性。

此外,useSyncExternalStore 還支援伺服器端渲染。透過傳遞 getServerSnapshot 引數,我們可以在伺服器端獲取儲存快照,從而避免客戶端和伺服器端渲染不一致的問題。

實際應用場景

useSyncExternalStore 非常適合用於以下場景:

  1. 全域性狀態管理:例如 Redux 或者 MobX,可以使用 useSyncExternalStore 來訂閱全域性狀態的變化。
  2. 外部資料來源:例如 WebSocket 或者其他實時資料來源,可以使用這個 Hook 來確保資料的一致性。
  3. 複雜元件通訊:在一些複雜的元件通訊場景下,使用 useSyncExternalStore 可以簡化狀態管理邏輯。

程式碼示例:與 Redux 整合

接下來,我們來看一個與 Redux 整合的示例。假設我們有一個簡單的 Redux store:

import { createStore } from "redux";
import { Provider, useSelector, useDispatch } from "react-redux";
import React, { useSyncExternalStore } from "react";

const initialState = { count: 0 };

function reducer(state = initialState, action) {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + 1 };
    default:
      return state;
  }
}

const store = createStore(reducer);

function useReduxStore() {
  return useSyncExternalStore(store.subscribe, store.getState, store.getState);
}

function Counter() {
  const state = useReduxStore();
  const dispatch = useDispatch();
  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
    </div>
  );
}

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

在這個示例中,我們建立了一個 Redux store,並使用 useSyncExternalStore 來訂閱 Redux store 的變化。這樣,我們可以確保元件在任何時候都能獲取到最新的狀態。

總結

useSyncExternalStore 是 React 18 中一個非常強大的 Hook,特別適用於需要確保狀態一致性的場景。透過本文的介紹和程式碼示例,希望大家能夠更好地理解和應用這個 Hook。如果你在專案中遇到了狀態不一致的問題,不妨試試 useSyncExternalStore

百萬大學生都在用的 AI 寫論文工具,篇篇無重複 👉: AI 寫論文

相關文章