SolidJS:For 与 Index

abc*_*abc 24 solid-js

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

<Index>组件是为这些情况提供的。根据经验,在使用基元时使用<Index>.

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

这两句话对我来说都没有意义。“使用基元时”是什么意思?我总是使用数组。有人可以澄清何时使用ForvsIndex吗?

art*_*tem 21

“使用基元时”是什么意思?我总是使用数组。

它与数组元素有关 - 无论它们是基元(如字符串数组)还是对象。

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

不同之处在于数组元素更改时 DOM 的更新方式。

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

因此,当您在数组中间插入一个元素时,each回调仅被调用一次 - 渲染插入的元素,并且其结果按照预期插入到数组中的 DOM 中。

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

FAQ中也对此进行了解释: for <For>each回调收到一个项目值和项目位置信号。对于<Index>,则相反 - 回调接收项目值的信号和项目位置的数字。

您可以在Solid Playground中尝试这个示例- 您可以打开控制台来查看<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'))

Run Code Online (Sandbox Code Playgroud)

  • 区别不在于比较,区别在于渲染。&lt;Index&gt; 将为移动或更改的数组元素重新渲染 DOM。如果元素是基元,则 DOM 只是显示基元值的文本节点,重新渲染文本节点没什么大不了的。如果元素是对象,则 DOM 通常会更复杂,包含显示对象所需的任何内容。&lt;For&gt; 不会重新渲染移动或更改的元素,它会移动 DOM 或执行嵌套更新,这比重新渲染整个对象更有效。 (2认同)

snn*_*snn 6

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

For在使用mapArray时内部使用。IndexindexArray

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

映射的项目使用项目本身作为键进行缓存:

const cache = {};
cache[item] = callback();
Run Code Online (Sandbox Code Playgroud)

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

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

对于indexArray,项目使用其在数组中的位置进行缓存。它更适合缓存基元,因为只要它们位于相同位置,缓存就会保持完整。

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

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