SolidJS: Differences between For and Index
Tags: solidjs, webdev, javascript
Published: 2023-05-11 11:41:24

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](https://www.solidjs.com/tutorial/flow_for) component is the best way to loop over an array of objects. As the array changes, <For> updates or moves items in the DOM rather than recreating them.

### Index

Solid also provides the [Index](https://www.solidjs.com/tutorial/flow_index) component, which will cause less rerenders in certain situations.

---

### For Example

```javascript
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 />;
```


![example site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ne0opj2to3vwm1jtnpa.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/962vdsjfbto37cf32m35.png)

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

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

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

---

## Index Example

```javascript
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 />
    </>
  );
}
```

![index component example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sahw9j0c6w5qomw7466t.png)

![no re-render even when the field of an object is changed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/efpgxowfnz5ipvw9rgjq.png)

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

```javascript
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>
    </>
  );
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/do8l8phpv2msvebdhq0d.png)

---

### Add a new item

```javascript
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 />
    </>
  );
}
```


![add new item](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oa8hlw1k32stblxvhrlz.png)

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!