SolidJS:对于与索引

SolidJS: For vs Index

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

The <Index> component is provided for these cases. As a rule of thumb, when working with primitives use <Index>.

<For> cares about each piece of data in your array, and the position of that data can change; <Index> cares about each index in your array, and the content at each index can change.

这些句子对我来说都没有意义。 “使用原语时”是什么意思?我总是使用数组。有人可以澄清何时使用 ForIndex 吗?

What does "when working with primitives" mean? I am always using an Array.

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

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

区别在于数组元素更改时 DOM 的更新方式。

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

因此,当您在数组中间插入一个元素时,each 回调仅被调用一次 - 以呈现插入的元素,并将其结果插入到 DOM 中的适当位置数组,如预期的那样。

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

FAQ 中也有解释:对于 <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'))

For 在内部使用 mapArray 函数,并在项目更新时使用 re-renders 项目。 Index 使用 indexArray 和 re-renders 更改的位,同时保留已呈现的元素。

假设您正在呈现项目列表。 mapArray re-renders 整个 liindexArray re-renders 表示项目值的 innerHTML。

基元或对象对项目的呈现方式没有影响。如果 item 是一个对象,mapArray 仍然是 re-renders 整个元素,indexArray re-renders 仅更新 属性。

import { createSignal, indexArray, mapArray } from 'solid-js';
import { render } from 'solid-js/web';

const [items, setItems] = createSignal([1, 2, 3, 4]);
let x = 0;
setInterval(() => setItems([1, 2, 3, x++]), 500);

const App = () => {
  return (
    <div>
      <ul>
        {mapArray(items, (item, index) => {
          // If an item updates, <li>...</li> will be re-rendered
          return (
            <li>#{index()}. {item} </li>
          );
        })}
      </ul>
      <ul>
        {indexArray(items, (item, index) => {
          // If item updates, only the value for `{item()}` will be re-rendered
          return (
            <li>#{index}. {item()} </li>
          );
        })}
      </ul>
    </div>
  );
}

render(App, document.querySelector('#app'));