SolidJS: For vs Index



在他们的渲染列表教程中,他们说:

为这些情况提供了<Index>组件。根据经验,使用基元时,请使用<Index>

<For>关心数组中的每一条数据,并且该数据的位置可以更改;<Index>关心数组中的每个索引,并且每个索引处的内容可以更改。

这两句话对我来说都没有意义;当使用基元"时;意思是我一直在使用数组。有人能说明什么时候使用ForIndex吗?

什么是"当使用基元"时;意思是我一直在使用数组。

这是关于数组元素的,无论它们是基元,如字符串数组中的基元,还是对象。

简而言之,如果您有一个对象数组,请使用<For>。如果您有一个字符串数组,而数组很短,或者您从未在数组中间插入或移除元素,请使用<Index>。否则使用<For>。如果您不确定,请始终使用<For>

不同之处在于,当数组元素发生更改时,DOM是如何更新的。

<For>总是检查元素在更改之前是否在数组中,并移动DOM节点以反映元素位置的更改,而不调用回调来呈现元素(如果在回调中使用index()信号来显示项目位置,它也会调用CCD_12,因此依赖于index()的内容将更新到位(。如果元素先前不在数组中,则<For>调用each回调以呈现更改后的元素。

因此,当您在数组中间插入一个元素时,each回调只调用一次,以呈现插入的元素,其结果将按预期插入到数组中的DOM中。

<Index>并没有这样做——它要简单得多,它只是比较每个索引中的新旧元素,如果它们不同,它会调用作为参数传递给each回调的item()信号。回调本身不会被调用,只有回调中依赖于item()信号的内容才会被更新到位。<Index>仅在数组末尾添加新元素时调用each回调。

常见问题解答中也有解释:对于<For>each回调接收到一个项目值和一个项目位置信号。对于<Index>,情况正好相反——回调接收一个表示项目值的信号和一个表示项位置的数字。

你可以在Solid操场上尝试这个例子——你可以打开控制台,看看<For><Index>:调用了多少次回调

import { render } from 'solid-js/web';
import { createSignal, For, Index } from 'solid-js';
function ForCats() {
const [cats, setCats] = createSignal([
'Keyboard Cat',
'Maru',
'Henri The Existential Cat'
]);

setTimeout(() => setCats(['Maru', 'Keyboard Cat', 'Keyboard Cat', 'New Cat']), 2000)
return (
<ul>
<For each={cats()}>{name => {
console.log(`For: rendered ${name} whole cat`);
return <li>
<a target="_blank" href="">
1: {name}
</a>
</li>
}}</For>
</ul>
);
}

function IndexCats() {
const [cats, setCats] = createSignal([
'Keyboard Cat',
'Maru',
'Henri The Existential Cat'
]);

setTimeout(() => setCats(['Maru', 'Keyboard Cat', 'Keyboard Cat', 'New Cat']), 2000)
return (
<ul>
<Index each={cats()}>{name => {
console.log(`Index: rendered ${name()} whole cat`);
return <li>
<a target="_blank" href="">
1: {name()}
</a>
</li>
}}</Index>
</ul>
);
}
render(() => <><ForCats /> <IndexCats/ ></>, document.getElementById('app'))

不同之处在于项目在更新周期之间的缓存方式。

CCD_ 28内部使用CCD_ 29,而CCD_。

mapArray在处理引用类型(如数组或对象(时非常有用。对于原始人来说,它们意义不大。

使用项目本身作为关键字来缓存映射的项目:

const cache = {};
cache[item] = callback();

项的位置对它们的缓存方式没有影响,因为它们的引用被用作键。好处是元素的位置可以在数组中移动,但其缓存保持不变。

因此,如果传递相同的对象,For将返回先前渲染的列表项。如果传递不同的对象,即使它具有相同的值,它也会返回一个新的列表项。为什么,因为对象是通过引用进行比较的。这两者即使具有相同的值也不相等:{name: 'John'} === {name: 'John'}

对于indexArray,使用项目在数组中的位置来缓存项目。它更适合缓存基元,因为只要它们处于相同的位置,缓存就会保持不变。

如果存在用于索引值的缓存元素,则Index返回先前呈现的列表项。这表现为细粒度更新。对于复合值(如{name: 'John'}(,将重新呈现属性,而不是列表项。

如果在更新周期之间传递的项目较少,则多余的项目将被清除。如果传递更多项目,则将装入新的列表项目。

最新更新