abc
abc

Reputation: 1559

SolidJS: For in child component not rendering list

I have a parent component returning:

<List list={list()}>
    {(item, index) => <div>{item}</div>}
</List>

where list is a created signal. List is a custom component I made returning:

<div>
    <For each={list}>{children}</For>
</div>

but whenever list is updated, it isn't rendered. When I move the For code to the parent, it renders, so what is it about passing a signal's value to a child component that makes it not rerender on updates?

EDIT: demo

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

function Counter() {
  const [list, setList] = createSignal([]);
  const increment = () => setList([...list(), 1]);

  return (
    <>
      <button type="button" onClick={increment}>
        add
      </button>
      <p>broken list</p>
      <List list={list()} />

      <p>other list</p>
      <For each={list()}>
        {(item) => <p>{item}</p>}
      </For>
    </>
  );
}

function List({list}) {
  return (
    <For each={list}>
      {(item) => <p>{item}</p>}
    </For>
  );
}

render(() => <Counter />, document.getElementById("app"));

EDIT 2: I meant to use <List list={list()} />, which also doesn't work, but I missed it earlier.

Upvotes: 4

Views: 3771

Answers (1)

artem
artem

Reputation: 51729

It does not work because destructuring props in Solid loses reactivity, that is, all the destructured props values do not update, ever.

Destructuring props is sometimes convenient and commonly used in other frameworks, but is not really recommended in Solid - the FAQ says:

By destructuring, you separate the value from the object, giving you the value at that point in time and losing reactivity.

You need to rewrite List component to use single props parameter and access props.list in the JSX:

function List(props) {
  return (
    <For each={props.list}>
      {(item) => <p>{item}</p>}
    </For>
  );
}

Why destructuring does not work? In Solid, props is an object, created behind the scenes by Solid, with getters for intercepting access to each individual property, like props.something. It's needed to track JSX (expressions and fragments) and effects (created by createEffect()) so that they are reevaluated and updated when props.something changes. There's no way to track access to properties which are destructured (well there's plugin for that, but it's not in the core framework because it has some overhead).

Upvotes: 9

Related Questions