-
-
Notifications
You must be signed in to change notification settings - Fork 984
Description
Describe the bug
I found that classList
(and possibly other HTML attributes) causes unnecessary re-runs. In the following code, createEffect
only reruns when v()
changes (I manually examined w.vs
). Similarly, HTML text re-runs only when v()
changes (I only get one render for ${i}
for the element, which was updated. Yet, every single change of any element (values()[i]
) I get classList for ${i}
for every single element in values()
. This is totally unexpected, especially considering that classList
and HTML renders are right next to each other.
import { createEffect, createMemo, createSignal, Index } from "solid-js";
export default function ClassListRerunExperiment() {
const names = createMemo(() => ['one', 'two', 'three', 'four', 'five', 'six', 'seven']);
const [values, setValues] = createSignal([1, 2, 3, 4, 5, 6, 7]);
function setOneValue(i: number, v: number) {
const next = [...values()];
next[i] = v;
setValues(next);
}
return <Index each={names()}>{(t, i) => {
console.log('Row render:', i);
const v = createMemo(() => values()[i]);
createEffect(() => {
if (i !== 0) return;
const w = window as any;
w.vs = w.vs ?? [];
w.vs.push(v());
});
return <div classList={{
'big': (console.log(`classList for ${i}`), v() >= 5),
}}>
{(console.log(`render for ${i}`), v(), 'z')}
<button onClick={() => setOneValue(i, v() - 1)}>-</button>
{v()}
<button onClick={() => setOneValue(i, v() + 1)}>+</button>
<button disabled={values()[i] <= 2}>Low</button>
{values().join(',')} {values()[i]}
</div>
}}</Index>;
}
I was able to track down the problem to this specific line:
<button disabled={values()[i] <= 2}>Low</button>
With this specific line removed, reactivity works as expected, any '-'/'+' press only results in a single classList for ${i}
log. Somehow, using values()
in 'disabled' attribute (maybe also any other HTML attribute?) seems to leak values()
as a dependency of classList
. At the same time, using values()
for rendering:
{values().join(',')}
does not cause any leakage.
Your Example Website or App
https://stackblitz.com/edit/solidjs-dependency-leakage-zqkzgank?file=src%2FApp.tsx
Steps to Reproduce the Bug or Issue
Open the link, open DevTools console.
Click any of the '-' or '+' buttons.
Expected behavior
Only one classList for ${i}
is logged exactly for the element being updated
Screenshots or Videos
No response
Platform
- OS: Windows, also Stackblitz, most likely cross-platform
- Browser: Edge, Opera, Yandex Browser
- Version: All latest
Additional context
No response