Solid: `force` setState doesn't trigger update inside keyed `For`

Created on 8 Jan 2020  路  6Comments  路  Source: ryansolid/solid

Reproducible demo: https://codesandbox.io/s/solid-force-list-3hvt3

Try edit the inputs with initial value 'hello' and click the button. The input inside keyed For doesn't update as expected.

ezgif-1-6f605588a634

bug

All 6 comments

Thanks for reporting. Super weird as Solid's For is always keyed and the keyed property is unnecessary(doesn't do anything). Something about it is screwing things up though. Probably a bug in force. I will investigate.

Thanks for instant reply. In the doc about Suspense there is an example using key. I'm curious about the reason why Solid doesn't need key to persist component state (input state, focus, etc.)?

Bad Copy and Paste from a React Example. Solid is based on mutation internally. It only renders once so I can use DOM node references as "keys". Sorting a list of DOM nodes is really just sorting a list of DOM nodes.

I figured out the problem. But it's not great. In a recent version, to reduce overhead of making too many fine-grained bindings I group them by template now. To improve performance I added simple diffing. So even if the change gets propagated there it is blocked. However single binding templates don't have it. Which produces an inconsistency. force only really has value for inputs so if this doesn't work its kind of worthless. However not diffing is a small overhead for all. I need to think on this.

I've thought of a couple ways of addressing this but I actually don't think I actually like them.

  1. Wrap each input value in its own binding. This will work in this scenario as you want but it sort of ties my hands on how I approach DOM updates. It basically re-enforces the inconsistency. This is the only place in the DOM we aren't doing a strict test and it doesn't come up often. I'd rather make this never work than try to make this the solution. What if you are using custom Web Components this way etc, the compiler would never know. I think it is perfectly valid for the library to take the stance that DOM updates should only be responsible for the state its aware of (like VDOM libraries like React). And too specific solution here will have long term potential downstream repercussions.

  2. Deprecating force to reduce confusion. I added force thinking it could help in this scenario although its use extends beyond this. Especially if the intention is to use state like signals. But I could argue, just use a signal then. The scenario I'm talking about is like time series, and RX type stuff where you are viewing each subsequent value as a sequence so the fact that the previous value is the same is irrelevant. Signals are basically made for this scenario of wiring stuff together. For example as a way of dispatching actions to a Store. It's perfectly fine to dispatch the same action multiple times in a row. That beings said force as an escape hatch has value. It just shouldn't be used for uncontrolled forms.

Which is unfortunate as this is the only scenario where this happens in the wild and I'd rather not change how bindings work (performance considerations), nor necessarily remove force, escape hatch scenarios for non-DOM updates. Although I'd definitely lean towards the latter. A similar discussion has come around removing index (2nd argument) from For since it will never update. I have solutions for that but it requires more complexity. There is a certain argument for just removing all potential footguns.

The challenge of course is there are solutions for these sort of problems but they will require a lot of documentation. In this case I can direct you to: https://reactjs.org/docs/uncontrolled-components.html. If we the intention is not to listen to input changes to update state (preferred approach) then use refs. Solid's refs are a bit different than Reacts. In this case either direct assignment with ref or forwardRef which calls a function with the ref could work. The challenge of course is if the list can be sorted your can't use index as the key to your refs array with the basic For component. In that case both the controlled/non-controlled forms sort of work similar in which you are mapping to a data structure for lookup.

This isn't a particular easy problem for React either in an uncontrolled way since if you bind to value every state re-render would reset all the inputs. This mixed form is really awkward for them. People are still trying to figure ways around it(https://github.com/reactjs/reactjs.org/issues/918). We don't have that problem, but you still have to do the same book keeping ultimately.

Thoughts? Is that reasonable?

===================
There is a 3rd option people might think of which is forceRender like React's forceUpdate but that will not work with Solid. Re-evaluating everything would not be Component scoped (there are no real Components) and it would cause a bunch of work possibly re-rendering parts of the DOM.

force is a little confusing, since diffing happens in some scenarios. State is just a snapshot of data, we should not use setState to represent a signal. I prefer deprecating force option and add some documents about unconntrolled forms.

Ok. I've deprecated force and written a note about forms. Thanks for your input.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

trueadm picture trueadm  路  4Comments

jcuenod picture jcuenod  路  7Comments

cliqqz picture cliqqz  路  3Comments

aguilera51284 picture aguilera51284  路  8Comments

Ziriax picture Ziriax  路  4Comments