DEV Community

SeongKuk Han
SeongKuk Han

Posted on

SolidJS: Differences between For and Index

There are For and Index Components in SolidJS to render array elements efficiently. array.map is inefficient as it always maps the entire array.


For

The For component is the best way to loop over an array of objects. As the array changes, updates or moves items in the DOM rather than recreating them.

Index

Solid also provides the Index component, which will cause less rerenders in certain situations.


For Example



import { For, createSignal } from "solid-js";

const initialPeople = [
  {
    name: "Amy",
    age: 15,
  },
  {
    name: "Bob",
    age: 25,
  },
  {
    name: "Charlee",
    age: 20,
  },
];

function ForComp() {
  const [people, setPeople] = createSignal(initialPeople);

  const changeAge = (personIdx) => () => {
    const newPeople = [...people()];
    newPeople[personIdx] = {
      ...newPeople[personIdx],
      age: Math.floor(Math.random() * 30),
    };
    setPeople(newPeople);
  };

  return (
    <>
      <For each={people()}>
        {(person, personIdx) => {
          console.log(`person(${personIdx()}) has rendered.`);

          return (
            <div style={{ cursor: "pointer" }} onClick={changeAge(personIdx())}>
              <h6>
                Name: {person.name} Age: {person.age}
              </h6>
            </div>
          );
        }}
      </For>
    </>
  );
}

function App() {
  return <ForComp />;


Enter fullscreen mode Exit fullscreen mode

example site

If the second item is clicked, the age of the second item will be changed like the following image.

the age of the second item has changed

If you change a part of an object, there would be no change on display.



 const changeAge = (personIdx) => () => {
    const newPeople = [...people()];
    newPeople[personIdx].age = Math.floor(Math.random() * 30);
    setPeople(newPeople);
  };


Enter fullscreen mode Exit fullscreen mode

This doesn't work because even though a field of the object is changed, the object remains the same.


Index Example



function IndexComp() {
  const [people, setPeople] = createSignal(initialPeople);

  const changeAge = (personIdx) => () => {
    const newPeople = [...people()];
    newPeople[personIdx] = {
      ...newPeople[personIdx],
      age: Math.floor(Math.random() * 30),
    };
    setPeople(newPeople);
  };

  return (
    <>
      <Index each={people()}>
        {(person, personIdx) => {
          console.log(`INDEX: person(${personIdx}) has rendered.`);

          return (
            <div style={{ cursor: "pointer" }} onClick={changeAge(personIdx)}>
              <h6>
                Name: {person().name} Age: {person().age}
              </h6>
            </div>
          );
        }}
      </Index>
    </>
  );
}

function App() {
  return (
    <>
      <h1>For</h1>
      <ForComp />
      <hr />
      <h1>Index</h1>
      <IndexComp />
    </>
  );
}


Enter fullscreen mode Exit fullscreen mode

index component example

no re-render even when the field of an object is changed

Index Component re-renders when index is changed while For component re-renders when its value is changed.

But you can still see the data is changed because person() is used in return.



return (
    <>
      <Index each={people()}>
        {(person, personIdx) => {
          console.log(`INDEX: person(${personIdx}) has rendered.`);
          const p = person();

          return (
            <div style={{ cursor: "pointer" }} onClick={changeAge(personIdx)}>
              <h6>
                Name: {p.name} Age: {p.age}
              </h6>
            </div>
          );
        }}
      </Index>
    </>
  );


Enter fullscreen mode Exit fullscreen mode

If you person() is used inside the render function, the data won't be changed. It's how SolidJS works.

no changes even when an item is clicked


Add a new item



import { For, createSignal } from "solid-js";

const initialPeople = [
  {
    name: "Amy",
    age: 15,
  },
  {
    name: "Bob",
    age: 25,
  },
  {
    name: "Charlee",
    age: 20,
  },
];

function ForComp() {
  const [people, setPeople] = createSignal(initialPeople);

  const changeAge = (personIdx) => () => {
    const newPeople = [...people()];
    newPeople[personIdx] = {
      ...newPeople[personIdx],
      age: Math.floor(Math.random() * 30),
    };
    setPeople(newPeople);
  };

  const addNewPerson = () => {
    setPeople(
      people().concat({
        people: "Delta",
        age: 50,
      })
    );
  };

  return (
    <>
      <button onClick={addNewPerson}>Add New Person</button>
      <For each={people()}>
        {(person, personIdx) => {
          console.log(`FOR: person(${personIdx()}) has rendered.`);

          return (
            <div style={{ cursor: "pointer" }} onClick={changeAge(personIdx())}>
              <h6>
                Name: {person.name} Age: {person.age}
              </h6>
            </div>
          );
        }}
      </For>
    </>
  );
}

function IndexComp() {
  const [people, setPeople] = createSignal(initialPeople);

  const changeAge = (personIdx) => () => {
    const newPeople = [...people()];
    newPeople[personIdx] = {
      ...newPeople[personIdx],
      age: Math.floor(Math.random() * 30),
    };
    setPeople(newPeople);
  };

  const addNewPerson = () => {
    setPeople(
      people().concat({
        people: "Delta",
        age: 50,
      })
    );
  };

  return (
    <>
      <button onClick={addNewPerson}>Add New Person</button>
      <Index each={people()}>
        {(person, personIdx) => {
          console.log(`INDEX: person(${personIdx}) has rendered.`);
          const p = person();

          return (
            <div style={{ cursor: "pointer" }} onClick={changeAge(personIdx)}>
              <h6>
                Name: {p.name} Age: {p.age}
              </h6>
            </div>
          );
        }}
      </Index>
    </>
  );
}

function App() {
  return (
    <>
      <h1>For</h1>
      <ForComp />
      <hr />
      <h1>Index</h1>
      <IndexComp />
    </>
  );
}


Enter fullscreen mode Exit fullscreen mode

add new item

For the new item, both renders the new item as well.


Conclusion

If you expect the data change doesn't need to be affected to rendering and index only matters, Index would be a good option then For for better performance.

I hope you found it useful in this article.

Happy Coding!

Top comments (0)