restate / v1.0.0

只訂閱需要的部分

選擇每個元件依賴的 store 部分,以 shallow 比較物件,以 batch 合併變化,並串接外部事件。

本頁內容傳入 selector動手試試以 shallow 選取多個欄位自訂比較函式用 batch 合併變化在 React 之外訂閱串接外部事件

傳入 selector

呼叫 Hook 時傳入一個函式,挑出元件需要的內容。每次變化後,restate 會執行 selector,並用 Object.is 與上一次的結果比較。若相等,元件就不會渲染。

留言改變了,ItemCount 會渲染嗎?

不會。它的 selector 仍回傳相同的商品數量,選取結果相等,所以不會請 React 渲染它。

JavaScript / JSX
const useCart = restate({ items: ['Book'], coupon: '', note: '' });

function ItemCount() {
  // Re-renders only when the number of items changes.
  const count = useCart((cart) => cart.items.length);
  return <p>{count} items</p>;
}

動手試試

修改欄位,觀察渲染計數器。關閉 shallow,看看每次都回傳新物件的 selector 會怎樣。

正在準備範例…

以 shallow 選取多個欄位

組出物件的 selector 每次都會回傳新物件,所以 Object.is 總是認為有變化。把 shallow 作為第二個參數傳入:它會逐一比較物件本身的欄位(只比較一層)。

shallow 也會對陣列、Map 與 Set 的元素做一層比較。

JavaScript / JSX
import { restate, shallow } from '@kkwaenggwari/restate';

function CartSummary() {
  const { count, coupon } = useCart(
    (cart) => ({ count: cart.items.length, coupon: cart.coupon }),
    shallow,
  );
  return (
    <p>
      {count} items · {coupon || 'no coupon'}
    </p>
  );
}

自訂比較函式

任何 (left, right) => boolean 函式都可以當作第二個參數。在 shallow 不夠用時使用,例如依 id 比較清單。

JavaScript / JSX
const ids = useCart(
  (cart) => cart.items.map((item) => item.id),
  (left, right) => left.length === right.length && left.every((id, index) => id === right[index]),
);

用 batch 合併變化

每次 set 都會立即通知訂閱者。當一個動作要改動多個 store 時,用 batch 包起來:記憶體會立即更新,訂閱者則在回呼結束後只執行一次。

JavaScript / JSX
import { batch } from '@kkwaenggwari/restate';

function checkout() {
  batch(() => {
    useCart.set((cart) => ({ ...cart, items: [] }));
    useOrder.set((order) => ({ ...order, status: 'paid' }));
  });
  // Subscribers run once, after both stores changed.
}

在 React 之外訂閱

subscribeSelector 只在選取的值改變時呼叫你,同樣支援選用的比較函式。

JavaScript / JSX
const stop = useCart.subscribeSelector(
  (cart) => cart.items.length,
  (count, previous) => analytics.track('cart-size', { count, previous }),
);

串接外部事件

restate 的第二個參數可以是 updater。它會在第一個元件或訂閱者開始監聽時啟動,在最後一個停止監聽時執行清理,所以瀏覽器事件、socket 或感測器只在需要時才連接。

用 start() 與 stop() 手動控制它。

JavaScript / JSX
import { restate } from '@kkwaenggwari/restate';

// Listens while at least one component or subscriber uses the store.
export const useOnline = restate(true, ({ setState }) => {
  const update = () => setState(navigator.onLine);
  window.addEventListener('online', update);
  window.addEventListener('offline', update);
  update();
  return () => {
    window.removeEventListener('online', update);
    window.removeEventListener('offline', update);
  };
});

搜尋文件

搜尋所有指南的標題、說明與內文。