在通过 Svelte each 块遍历对象时查找值

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

我是 Svelte 的新手。关于最有效的方法是什么有什么想法吗?我的第一种方法是最好的吗(或者我偏离了基础)?

我会说答案只取决于数据中发生的事情。

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

这是一个示例(复制粘贴到 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 and/or schedule.locations,那么您可能需要考虑添加某种形式的缓存。 Svelte 监视整个数组或对象的变化,所以如果你想实现可以根据单个项目变化进行缓存的东西,你可能需要手动实现很多缓存机制。

如果数据按时呈现且未更改,则缓存或反规范化几乎没有好处(无论如何在性能方面)。