Search code examples
solid-js

SolidJS: For vs Index


In their tutorial for rendering lists, they say:

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

and

<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.

Neither of these sentences makes sense to me. What does "when working with primitives" mean? I am always using an Array. Could someone clarify when to use For vs Index?


Solution

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

    It's about array elements - whether they are primitives, as in an array of strings, or objects.

    In short, if you have an array of objects, use <For>. If you have and array of strings, and the array is short or you don't ever insert or remove elements in the middle of the array, use <Index>. Otherwise use <For>. If you are not sure, always use <For>.

    The difference is how the DOM is updated when array elements are changed.

    <For> always checks if an element was in the array before the change, and moves DOM nodes to reflect the change of element position, without calling the callback to render the element (it will also invoke the index() signal if it was used in the callback to show item position, so the stuff that depends on index() will be updated in place). <For> calls the each callback to render the changed element if the element was not previously in the array.

    So, when you insert an element in the middle of the array, the each callback is called only once - to render inserted element, and its result is inserted into DOM in place in the array, as expected.

    <Index> does not do that - it's much simpler, it just compares old and new elements at each index, and if they differ, it invokes the item() signal that was passed as parameter to the each callback. The callback itself will not be called, only the stuff inside the callback that depends on the item() signal will be updated in place. <Index> calls each callback only when new elements are added at the end of the array.

    It's also explained in the FAQ: for <For>, the each callback received an item value and a signal for item position. For <Index>, it's the opposite - the callback receives a signal for item value, and a number for item position.

    You can try this example in the Solid playground - you can open the console to see how many times the callback is called by <For> and <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'))