dmjio / miso

:ramen: A tasty Haskell front-end framework
https://haskell-miso.org
BSD 3-Clause "New" or "Revised" License
2.18k stars 133 forks source link

Keyed nodes documentation #745

Open functora opened 7 hours ago

functora commented 7 hours ago

It would be nice to have more documentation about keyed nodes, and the cases where they should be used, where should not be used and how to use them. In Miso code itself are just only a couple specific keyed tags like trKeyed and liKeyed, does it mean keyed nodes should be used only with 2 tags, or if I have a dynamic list of div or input tags - they also should be keyed? I'm asking because I think I might have some issues with dynamic lists of input tags in my apps, when adding and removing in runtime input tags in specific order, the content text inside the input field was put into the wrong place at some point - the text was kinda duplicated if nodes were next to each other. I solved it in an ugly way, running small JSM script to sync input views with input models. Not sure the issue was related to keyed nodes, but if feels like it might be. https://github.com/functora/functora.github.io/blob/8775227a3c8d06635677229a43cc4350e3a04d0b/ghcjs/currency-converter/src/Main.hs#L284-L295

dmjio commented 6 hours ago

Hey,

So the keys are supposed to turn the quadratic behavior of modifying large child lists into a linear time operation, and in some happy-path cases even better. If a key attribute is present on a node then miso will attempt to "sync children" according to some heuristics.

The process is documented here in syncChildren.

https://github.com/dmjio/miso/blob/master/jsbits/diff.js#L187

Now I will say if you don't have a key node on all the children in the lists it could cause odd behavior. That might be what you're seeing (duplication etc.), since that's not currently statically enforced, so be sure to check a key is present on all nodes in a child list, and that the keys are unique. Otherwise, if you're using the isomorphic functionality there could be a case where text nodes get combined into a single text node.

If the above cases don't describe what you're seeing I'd recommend attempting to reproduce the duplication behavior as minimally as possible and we can follow up on it with a bug report.

dmjio commented 6 hours ago

Also, if you're attempting to manipulate the DOM outside of miso, then this can cause undefined behavior. In specific cases where you're operating on a single DOM element it can work fine with the lifecycle hooks. In general I'd say when dealing with child lists you shouldn't need to manipulate things by hand.

Secondly, you can always remove the key attribute and stuff should work just fine. key is purely an optimization when operating on large lists that have a lot of mutations that occur to them

dmjio commented 6 hours ago

We also use the keyed stuff for benchmarks, and have them tested here:

https://github.com/dmjio/miso/blob/master/tests/diff.test.js

functora commented 4 hours ago

Thanks for reply, @dmjio ! So the keyed is basically an optimization, but there is no reason to not have it in any kind of repeating tags, not only tr and li? The issue with dynamic repeating input and textarea tags mixing the text values of neighbour nodes after node removal is old one, and exists for sure. I was encountering it before with more "pure" examples, unlike example I provided where material design components javascripts theoretically could mess it up. Another issue I "solved" with this syncInputs script was input and textarea cursor being slow, unresponsive and/or jumping around if I set the value attribute in Miso view. It is especially noticeable if user types text into input or textara "too fast". So I didn't set value attribute from Miso view, and syncing value with this script after every update. It's a separate issue, but I still would like to ask - should I use "controlled input" with Miso or not? Could slow update or view function break the controlled inputs in a way I described?