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

Svelte 5中派生嵌套字典的细粒度 reactivity 实现方案

Svelte 5 嵌套大对象的细粒度响应式派生方案

需求场景

你有一个规模可能很大的嵌套响应式状态:

let a = $state({
  foo: {bar: {baz: {name: "x", value: 4}}},
  unrelated: 42
});

需要派生一个对象b,满足b[x][y].newValue = a[x][y].value * 2,最终得到:

b = {foo: {bar: {baz: {newValue: 8}}}}

直接用$derived会在a的任意字段变更时全量重算整个b,无法适配大规模数据。需要在供组件加载的Class中实现细粒度响应,确保修改a[x][y].name这类非目标字段时,不会触发b对应节点的更新。

实现方案

核心思路是为每个包含value的节点创建独立的细粒度派生值,通过Proxy懒加载派生节点,避免提前遍历整个大对象,同时利用Svelte 5的$state和$derived实现精准依赖跟踪。

完整Class代码

class DerivedNestedState {
  #originalState;
  #derivedRoot;

  constructor(originalState) {
    this.#originalState = originalState;
    this.#derivedRoot = this.#createDerivedProxy(originalState);
  }

  get b() {
    return this.#derivedRoot;
  }

  #createDerivedProxy(originalNode) {
    // 非对象类型直接返回
    if (typeof originalNode !== 'object' || originalNode === null) {
      return originalNode;
    }

    // 用$state创建响应式缓存,存储已生成的派生节点
    const cache = $state({});

    return new Proxy(cache, {
      get: (target, prop) => {
        // 缓存命中直接返回
        if (prop in target) {
          return target[prop];
        }

        // 生成newValue:仅当原节点存在value字段时创建独立派生值
        if (prop === 'newValue' && 'value' in originalNode) {
          const derivedValue = $derived(originalNode.value * 2);
          target[prop] = derivedValue;
          return derivedValue;
        }

        // 递归处理嵌套对象属性
        const originalChild = originalNode[prop];
        if (typeof originalChild === 'object' && originalChild !== null) {
          const derivedChild = this.#createDerivedProxy(originalChild);
          target[prop] = derivedChild;
          return derivedChild;
        }

        // 非对象属性直接返回原数据
        return originalNode[prop];
      }
    });
  }
}

使用示例

// 初始化原状态
let a = $state({
  foo: {bar: {baz: {name: "x", value: 4}}},
  unrelated: 42
});

// 创建派生状态实例
const stateService = new DerivedNestedState(a);

// 访问派生值
console.log(stateService.b.foo.bar.baz.newValue); // 输出 8

// 修改原状态的value,触发对应派生值更新
a.foo.bar.baz.value = 5;
console.log(stateService.b.foo.bar.baz.newValue); // 输出 10

// 修改原状态的name,派生值不会更新(无多余计算)
a.foo.bar.baz.name = "y";
console.log(stateService.b.foo.bar.baz.newValue); // 仍输出 10

关键特性说明

  • 懒加载派生:通过Proxy拦截属性访问,只有当实际访问b的某个节点时才会生成对应的派生内容,避免初始化时遍历整个大对象。
  • 细粒度依赖:每个newValue都是独立的$derived值,仅跟踪对应原节点的value字段,其他字段变更不会触发它的更新。
  • 响应式缓存:用$state维护缓存,确保派生节点的访问能被Svelte的响应式系统正确跟踪,组件使用时能自动更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:03:12