【问题标题】:How to filter a svelte store using a dynamic filter如何使用动态过滤器过滤苗条的商店
【发布时间】:2020-05-15 11:40:16
【问题描述】:

我有一个派生商店,它必须使用过滤器的 HTML 选择来过滤条目对象。现在我引入了一个额外的过滤器存储(可观察)来强制派生存储回调在过滤器存储更改时运行。

但是当过滤器更改时,是否可以在没有过滤器存储的情况下触发下面派生存储中的回调?我需要这个额外的商店吗? 下面的代码工作正常。我很好奇。

import { writable, derived } from 'svelte/store';
import { entries } from './../stores/entries.js';

export const filter = writable({
  // to update filter use: $filter.kind = ... 
  // or: filter.update(o => Object.assign(o, {kind: .., batchId: ...}));
  batchId: 'all',
  kind: 'all',
});

let list, total;

export const view = derived(
  [filter, entries], 
  ([$filter, $entries], set) => {

    total = 0;

    if ($entries) {
      // filter by HTML selects: kind, batchId
      list = Object.keys($entries.map).sort().reduce((a, key) => {
        if ((['all', $entries.map[key].description.kind].includes($filter.kind))
          && (['all', $entries.map[key].parentId].includes($filter.batchId))) {
            total += $entries.map[key].grossValue;
            a.push($entries.map[key]);
        };
        return a;  
      }, []);
      set({list, total});
    };

    return () => {
      set(null);
    };
  }, null
);

更新:使用自定义存储的伪派生可写对象

import { writable, derived } from 'svelte/store';
import { entries } from './../stores/entries.js';

let list, total;

const filter = writable({batchId: 'all', kind: 'all'});

export const view = () => {
  const viewDerived = derived([filter, entries], 
    ([$filter, $entries]) => {

      total = 0;
      if ($entries) {
        // filter by HTML selects: kind, batchId
        list = Object.keys($entries.map).sort().reduce((a, key) => {
          if ((['all', $entries.map[key].description.kind].includes($filter.kind))
            && (['all', $entries.map[key].parentId].includes($filter.batchId))) {
              total += $entries.map[key].grossValue;
              a.push($entries.map[key]);
          };
          return a;  
        }, []);
        return {list, total};
      } else return null;

    }
  );
  // custom store methods
  return {
    subscribe: viewDerived.subscribe,
    set: filter.set,
    update: (obj) => filter.update(o => Object.assign(o, obj)),
    reset: () => filter.set({batchId: 'all', kind: 'all'}),
  };
}();

【问题讨论】:

  • 这是在组件中运行吗? derived 在组件之外并不能真正工作,因为 Svelte 不会跟踪 .js 文件中的依赖关系。
  • 商店做得很好。

标签: observable reactive-programming svelte


【解决方案1】:

您可以将派生存储中的逻辑提取到您自己控制的函数/对象中,并使用 API 手动触发更新……但这不是一个好主意。这会破坏一些封装而没有任何好处。

您的writable + derived 解决方案是,IMO,最直接和优雅的解决方案。它明确地概述了数据依赖关系,并清晰地分离了关注点,不涉及神秘代码。它还为 Svelte 提供监控更改所需的功能,并以最精细的粒度自动为您管理订阅。

这是一个很好的模式,非常适合您的用例。我会一直这样。

【讨论】:

  • OK rixo 和 thnx。我是否使用 store.set / update 或 $store 绑定和 $store.prop 分配来更改过滤器?
  • 不,$store 分配在内部使用了商店的set 方法。这是一层非常薄的语法糖,所以完全一样。
  • 我注意到当我更改过滤器道具时回调运行了几次。我还没有弄清楚过滤器道具更改和回调之间的关系。例如:如果我更改选择绑定(更改选择选项),上述示例中的回调会触发 3 次。有时回调会运行六次。
  • 在一个简单的案例中我只得到一个更新:svelte.dev/repl/f8d2249416b845faa2389d33d0af490f?version=3.22.2。话虽如此,我最近看到了多份关于人们在另一个组件中使用绑定时进行双重更新(在反应块中)的报告。这可能是相关的。此外,如果您有多个连续触发的$store.foo 分配,那么您可能会获得多个更新。所以也许,通过自己使用set / update,你可以“批量”这些更改,事实上......
  • 是的。从其他组件中选择绑定。我使用更新来批量过滤更改。但是复选框绑定也会使用以下命令触发两次:bind:checked={$entryFilter.compact}。如果有一个用于 Svelte 的工具来记录这些脏/反应信号的来源,那就太好了。再次Thnx,我会尝试找到源代码。
猜你喜欢
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-19
  • 1970-01-01
相关资源
最近更新 更多