Reputation: 11
Is this normal that each list item in Solidjs is mounting on every change?
import { Component, createSignal, For } from 'solid-js';
const data = [
{name: 'Helen'},
{name: 'Peter'},
{name: 'Maksim'},
]
const Card: Component = (props: {name: string}) => {
console.log('card'); // It runs on every click which I'm not expecting
return <div>
<span>Name: </span>
<span>{props.name}</span>
</div>
}
export const App: Component = () => {
const [users, setUsers] = createSignal(data)
return (
<>
<button onClick={() => setUsers(users => users.map(user => ({...user, name: 'Suzy'})))}>Click</button>
<For each={users()}>{user => <Card {...user} />}</For>
</>
);
};
The same happens with createStore.
Upvotes: 0
Views: 236
Reputation: 13698
That is normal because you are updating every list item inside setUsers
by mapping over items and creating a new object that has the same values. Although you use previous values, you are creating new object.
For
keeps the reference of an item if the array item does not change. Its internal logic is something like this:
const cache = {};
cache[user] = <Card />
Since you are changing every array items, invalidating the cache by throwing away the old key, hence a new item is rendered. When this new item is rendered, Card
is mounted.
Try this code, in this one we are updating only the first item:
import { Component, createSignal, For } from 'solid-js';
import { render } from 'solid-js/web';
const data = [{ name: 'Helen' }, { name: 'Peter' }, { name: 'Maksim' }];
const Card: Component<{ name: string }> = (props) => {
console.log(props.name);
return (
<div>
<span>Name: </span>
<span>{props.name}</span>
</div>
);
};
export const App = () => {
const [users, setUsers] = createSignal(data);
const handleClick = () =>
setUsers((users) => [
...users.map((val, i) => (i === 0 ? { ...val } : val)),
]);
return (
<>
<button onClick={handleClick}>Click</button>
<For each={users()}>{(user) => <Card {...user} />}</For>
</>
);
};
render(App, document.body);
Upvotes: 1