在通过 Svelte each block 迭代对象时查找值

问题描述

以下简化示例有效,但不确定它是最有效的方法,因为我在每次迭代的每个块中多次调用 getLocation()

<script>
  export let schedule = {
    locations: [
      {
        _id: 1,name: 'Boston',parking: 'Onstreet'
      },{
        _id: 2,name: 'New York',parking: 'Paid lot'
      }
    ],sections: [
      {
        locationId: 2,day: 1
      },{
        locationId: 1,day: 2
      }
    ]
  }

  function getLocation(id) {
    return schedule.locations.find( ({ _id }) => _id === id )
  }
</script>

<template>
  {#each schedule.sections as section}
    <p>{getLocation(section.locationId).name} {getLocation(section.locationId).parking}</p>
  {/each}
</template>

我可以使用的其他方法

  1. 以 locationId 为键,以 location 对象为值填充 Map 对象,并在每个块中引用它。我想它可能有更多的开销,因为我必须构建地图,然后每次都按键查找值。
  2. 显示之前通过向节对象添加位置属性来对数据进行非规范化。当我传递数据时,不想改变它或有克隆的开销。
  3. 这个看起来很容易,但由于迭代可能效率较低...创建一个单元素数组,其中包含从 getLocation() 返回的位置对象,并使用内部 each 块来访问这样的位置属性.. .
<template>
  {#each schedule.sections as section}
    {#each [getLocation(section.locationId)] as location}
      <p>{location.name} {location.parking}</p>
    {/each}
  {/each}
</template>

我是 svelte 的新手。关于最有效的方法是什么的任何想法?我的第一个方法是最好的(还是我离基地很远)?

解决方法

我认为答案取决于数据中的情况。

我通常尽量避免使用任何函数作为模板的一部分(不包括动作)。这种默认做法来自使用 Vue2,其中计算的使用可以很容易地用于注入缓存数据,而不是在重新渲染时就地计算。不过,我发现反应性在确定要更新组件内的哪些部分方面做得非常好。

这是一个示例(复制粘贴到 repl

<script>
    const list = ['uno','dos','tres','catorce'];
    let somethingRandom = true
    const splitWord = (word) => {
        console.log(`split [${word}]`)
        return word.split('')
    };
</script>

{#each list as word}
<div>
    {#each splitWord(word) as letter}
        <span>{letter}</span>
        <input type="checkbox" bind:checked={somethingRandom}> <!-- causes re-render-->
    {/each}
</div>  
<input bind:value={word}> <!-- causes re-render -->
<input type="checkbox" bind:checked={somethingRandom}><!-- does not cause to re-render -->
{/each}
  • 只要您在内循环 (<input type="checkbox" bind:checked={somethingRandom}>) 中有 {#each splitWord(word) as letter},就会重新渲染内部循环。

  • 如果您将内部 somethingRandom 输入注释掉并且只在外部循环中包含它,则更改 somethingRandom 值不会导致内部循环重新渲染。

  • 更改 <input bind:value={word}> 会导致内部重新渲染

  • 总是重新渲染整个 list

因此,如果您有一个庞大的数据集并且正在编辑 schedule.sections 和/或 schedule.locations,那么您可能需要考虑添加某种形式的缓存。 Svelte 监视整个数组或对象的更改,因此如果您想实现可以根据单个项目更改缓存的内容,您可能需要手动实现很多缓存机制。

如果数据按时呈现,并且不会改变,那么缓存或反规范化几乎没有任何好处(在性能方面)。