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);
  };
});

搜索文档

搜索所有指南的标题、描述和正文。