BridgeCraft logobridgecraft
週報顧問服務作品集關於聯絡登入
聯絡

bridgecraft

從資料視覺化到 AI Agent,一直在找下一個 meta

文章主題指南週報顧問服務Labs作品集系統架構關於聯絡RSS

© 2026 BridgeCraft — Waiting7777. All rights reserved.

← 所有文章

React 18 - useSyncExternalSource

2022年3月15日 · Waiting7777 · 2 分鐘閱讀

當 useMutableSource 遇上 redux

起因在當初 useMutableSource 的範例時:

import { useSelector } from "react-redux";

function Example() {
  // The user-provided selector should be memoized with useCallback.
  // This will prevent unnecessary re-subscriptions each update.
  // This selector can also use e.g. props values if needed.
  const memoizedSelector = useCallback(state => state.users, []);
  
  // The Redux hook will connect user code to useMutableSource.
  const users = useSelector(memoizedSelector);

  // ...
}

原本建議要把 getSnapshot 這個 function memoize 起來,不然會導致每次 re-render 的時候都會 re-subscription。

結果這造成了廣泛的討論,有人認為是過早最佳化。

另外一個問題是,在大家現有的 codebase 裏面,早就充滿了使用匿名 function 的 useSelector

const todos = useSelector(state => state.todos)

const todo = useSelector(state => selectTodoById(state, id))

如果要用新的 useMutableSource 要把舊的 redux code 全部都補上 useCallback ,實在太辛苦了。

Concurrent reads, synchronous updates

另一個問題是,在 react 18 之後用 fiber 實作了稱之為最小單位為 fiber 的更新方式,所以一次 render 有可能拆分成多個 fiber,那麼用到外部狀態時問題就來了,有可能前一個 fiber 跟後面一個fiber時 外部狀態已經改變,這時會直接觸發 subsciption 那麼這個 callback 跟 fiber 的順序就變得不可靠。

useMutableSource → useSyncExternalSource

經過了眾多的討論,為了讓外部 store 的更新是可靠的,最後決定了讓這個更新退回成同步的更新,

在他們新的設計下:

  • store change 觸發的更新會是同步的 , 就算有用 startTransition

  • 作為交換,built-in 的狀態更新絕對不會被 subscription 蓋掉,就算他們在同個 render 下接收

為了更好的符合這個改動,就決定把原本的 useMutableSource 改名了。

API Overview

import {useSyncExternalStore} from 'react';

// We will also publish a backwards compatible shim
// It will prefer the native API, when available
import {useSyncExternalStore} from 'use-sync-external-store/shim';

// Basic usage. getSnapshot must return a cached/memoized result
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);

// Selecting a specific field using an inline getSnapshot
const selectedField = useSyncExternalStore(store.subscribe, () => store.getSnapshot().selectedField);

新版的 api 不用告訴它 store 在哪,而是直接告訴它怎麼拿到資料的快照 getSnapshot 。

// Name of API is not final
import {useSyncExternalStoreWithSelector} from 'use-sync-external-store/with-selector';
const selection = useSyncExternalStoreWithSelector(
  store.subscribe,
  store.getSnapshot,
  getServerSnapshot,
  selector,
  isEqual
);

並且給出了額外的 api 供使用。

結論

目前感覺這個 api 還很不穩定,根據 react conf 目前 Redux 確定會用 useSyncExternalStore 改寫,但它們改寫的過程中會不會再遇到問題導致 api 要修改就不得而知了。

另外這次很大一部分問題是 react 18 用了 fiber 後 render 不再 blocking ,當 render 交出控制權的時候,外部資料更新導致到底要如何處理的問題。

參考資料

https://github.com/reactwg/react-18/discussions/86 https://www.zhihu.com/question/502917860

每週一篇 — 技術趨勢背後的商業邏輯

分享:

Waiting7777

WoW Arena 冠軍轉前端,用電競 meta 思維拆解技術趨勢。

關於作者

相關文章

YC 裡越來越多二次創業者 — AI 時代為什麼老手反而更吃香創業創投+4

YC 裡越來越多二次創業者 — AI 時代為什麼老手反而更吃香

為什麼 AI 時代反而讓「老手」更吃香?從 YC 的數據看 repeat founder 的優勢在哪,以及這對第一次創業的人有什麼啟示。

2026年8月12日 · Waiting7777 · 7 分鐘閱讀

繼續閱讀 →
OpenChamber:專為 AI Agent 設計的開發環境,跟 IDE 的差別在哪?AI Agents開發工具+5

OpenChamber:專為 AI Agent 設計的開發環境,跟 IDE 的差別在哪?

拆解 OpenChamber 的設計邏輯:為什麼 agent 需要專屬的開發環境、跟直接在 terminal 跑 Claude Code 有什麼本質差異,以及這個方向的商業潛力在哪。

2026年8月11日 · Waiting7777 · 8 分鐘閱讀

繼續閱讀 →
AI coding 工具燒錢有多快?Databricks 告訴你怎麼控成本AI開發工具+4

AI coding 工具燒錢有多快?Databricks 告訴你怎麼控成本

從「Databricks 燒完錢才搞出控制工具」這個角度切入,拆解 AI coding 工具的真實成本結構,以及企業在 scale up 後才發現的坑。對比 Rippling 同樣在燒錢後才蓋 ROI 工具,這是一個系統性問題。

2026年8月8日 · Waiting7777 · 7 分鐘閱讀

繼續閱讀 →

這篇文章對你有幫助嗎?

每週一篇 — 技術趨勢背後的商業邏輯

AI 產業在變什麼、工程師該注意什麼——拆清楚寄到你的信箱。