如何防止重新渲染大列表?

时间:2020-05-22 06:31:35

标签: lit-element

我有一个用于游戏编辑器的60x30网格,随着单元的更新,将创建一个新数组来保存状态。

问题在于,当我更新该网格数组时,这会更改属性,并导致render()重新创建网格。这似乎几乎是显而易见的,但是那我的选择变成了什么?

如果这过于具体,请想象只是一个巨大的项目列表,并且您有一个不变的数组,其中的一项属性必须更改。

 render() { 
    return html`
      ${this.data?.cells.map((row) => {
        return row.map((cell) => {
          return html`<editor-cell .data="${cell}"></editor-cell>`;
        });
      })}
    `;
  }

巧合的是,我在Angular上遇到了同样的问题,因为它只有一个trackBy使用for循环,而{{1}}使用了index或item.id来防止重新生成项目列表。我只是为此接受了独角兽,但这是同样的问题。

问题:

我在这里对不可变状态缺少什么?我完全理解为什么会发生这种情况,它是一个新数组,所以点亮的元素只会呈现它认为是新数组的内容。我想要那个,但是一旦渲染了网格,我就不理解渲染和数据更新之间的分离。我或者缺少对生命周期的关键理解,或者我的状态处理方法完全是错误的。

1 个答案:

答案 0 :(得分:0)

如果您更新了整个数组,则会更改内存引用,然后lit-html必须重新渲染整个数组,因为它不知道哪些项会更改。

在lit-html文档中,您可以找到有关Repeating templates的内容,对此进行了很好的解释。

在这种情况下,您应该使用repeat指令,该指令可根据用户提供的键对列表进行有效的更新:

render() { 
  return html`
    ${repeat(this.data?.cells, row => row.id,
      row => html`${repeat(row, cell => cell.id,
        cell => html`<editor-cell .data="${cell}"></editor-cell>`
      )}`
    )}
  `;
}

请注意第二个参数的重要性,它是每个项目保证的唯一键。