You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为React的useSyncExternalStore配置自定义相等比较器?

解决useSyncExternalStore数组引用导致的不必要重渲染问题

useSyncExternalStore本身不支持直接传入自定义比较函数,但可以通过包装快照函数的方式,实现自定义内容比较的效果,避免JSON序列化带来的性能损耗。

核心思路是:缓存上一次的快照引用,在getSnapshot阶段先对比当前快照和缓存快照的内容,如果内容一致,就返回缓存的旧引用,让Object.is判断为相等,从而跳过重渲染;如果内容不同,再更新缓存并返回新快照。

实现代码示例

针对数组的场景,我们可以封装一个自定义Hook,搭配浅比较(或深比较)函数来处理:

import { useSyncExternalStore, useRef } from 'react';

// 数组浅比较函数:适用于元素为基本类型的场景
function shallowEqualArrays(a, b) {
  if (a === b) return true;
  if (a.length !== b.length) return false;
  for (let i = 0; i < a.length; i++) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

// 包装useSyncExternalStore,添加自定义比较逻辑
function useCustomExternalStore(subscribe, getSnapshot) {
  const snapshotRef = useRef();

  const customGetSnapshot = () => {
    const currentSnapshot = getSnapshot();
    
    // 针对数组做自定义内容比较
    if (Array.isArray(currentSnapshot)) {
      if (shallowEqualArrays(currentSnapshot, snapshotRef.current)) {
        return snapshotRef.current; // 返回旧引用,跳过重渲染
      }
    } else {
      // 非数组类型保留默认Object.is判断
      if (Object.is(currentSnapshot, snapshotRef.current)) {
        return snapshotRef.current;
      }
    }

    // 内容不同时更新缓存并返回新快照
    snapshotRef.current = currentSnapshot;
    return currentSnapshot;
  };

  return useSyncExternalStore(subscribe, customGetSnapshot);
}

使用说明

  • 如果数组元素是引用类型(比如对象),可以把shallowEqualArrays替换为深比较函数,但要注意优化深比较的逻辑,只对比必要的字段,避免不必要的性能开销。
  • 这个方案的性能远优于JSON序列化,因为直接做数组元素的逐次对比,没有序列化/反序列化的额外消耗。
  • 缓存的快照用useRef存储,确保跨渲染周期保留引用,不会被React的渲染机制重置。

内容的提问来源于stack exchange,提问作者siim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 11:04:54