#Fine grained reactivity for arrays

3 messages · Page 1 of 1 (latest)

limber remnant
#

I noticed that <Index> and <For> aren't really using "fine grained reactivity", while they possibly could (?) for stores or arrays of signals. Each time any single value changes, they actually do comparison between old & new array elements and apply changes accordingly. This seems like more of a React way than Solid.

Of course it's still fast, but there's way to make it faster.

For example

let current = 0;
const getNext = () => `${++current}`;
const [s, set] = createStore(Array.from({ length: 10000 }).map(getNext)); //["0", "1", "2", ..., "9999"]

return <Index each={s}>
  {(v, i) => {
    return <input
      value={v()}
      onInput={(e) => set(i, e.target.value)}
    />
  }}
</Index>

here on input set goes on for ~5ms on my pc, that's mainly the calculations that compare old & new array. So to make it even faster, we can rewrite that to

<Index each={new Array(s.length)}>
  {(_, i) => {
    return <input
      value={s[i]}
      onInput={(e) => set(i, e.target.value)}
    />
  }}
</Index>

here on input set goes on for ~0.04ms, that's mainly because of this "fine grained reactivity". The new Array(s.length) is important here, it's to not give the <Index> any values to process, and then use directly s[i]. Result is the same, just faster.

Do we need something like that? (it wouldn't create unused signal)

<JustIndex length={s.length}>
  {(i) => {
    return <input
      value={s[i]}
      onInput={(e) => set(i, e.target.value)}
    />
  }}
</JustIndex>

Also if there's way to detect if array is store ($TRACK in newItems), or when array elements are signals, then maybe indexArray could be improved to use this fine grained reactivity.
Or make value argument optional, and if not used, there's no need to detect changes between elements of new & old arrays nor create their signals, because with current component, the new Array(s.length) just bothers me if you could just pass s having eg. this optional argument.

limber remnant
#
  • Improved in a way that v() could be just wrapper for () => s[i], But idk how this could be implemented.

Also if s was just signal, my example still works with s()[i], better yet createMemo(() => s()[i]), but performance would actually be worse compared to current <Index> implementation (4ms direct memoed signal vs 1ms comparing arrays)

chilly urchin