purescript-halogen/purescript-halogen

Component rendered improperly when raising messages during initialization

simonolander opened this issue · 5 comments

SSCCE

https://try.purescript.org/?gist=0b8ea8a9d25aa093b1876278d45e09f0

Expected

Child component should render "Initialized" after initialization.

Actual

Child component renders both "Loading..." and "Initialized" after initialization.

Leads

The following changes, individually, makes the problem disappear:

  • Changing text "Loading... to p_ [ text "Loading..." ] in the child component
  • Removing the connect ... in the child component
  • Removing the raise ... in the child component
  • Changing div_ [ slot ... ] to slot ... in the parent component
  • Removing the handling of the message in the parent component
garyb commented

I think this is a duplicate of #657. The main trigger here is the purescript-halogen-store machinery, as from looking at the code of that it looks like it will render a "naked" slot as the HTML for the component returned by connect.

garyb commented

There's something tricky going on here. I've not managed to replicate this without using halogen-store as in this case, or halogen-hooks as in the linked repo in the other issue. I've tried a few things, but mustn't have quite replicated the exact states that those libraries pass through yet.

At least there's one piece of information I have now, that this isn't caused simply by using a slot as the render product for a component, nor a nested arrangement of such.

garyb commented

I know what's happening now, but not exactly how the state arises. It's really odd that it requires at least a three-deep component hierarchy to trigger it, it seems like if it happens with three it should be reproducible with two, but I've not managed to do that yet.

There are a number of conditions required for this bug to occur, but one of them is that the innermost component that is rendering the content must change its root DOM node. So from HH.text "" to a HH.div, or a HH.hr to a HH.p, or whatever. When it renders a consistent top level node, I've not seen any of these kinds of problems occur (that's not a fix or workaround, just a comment on the conditions that are buggy).

From liberally logging the processes going on, something happens such that we process a Step for a component where it has the initial value for the root element of the component rather than the current. So if it was first rendering HH.hr and then some HH.div ..., it does what it should in one place to render the new stuff, but then it encounters the Step for the component again afterwards, which has the HH.hr still, so it patches it back in. I've observed it halting the element that is removed, producing the new Step with the correct node, and then it somehow the earlier version of it appears again later on in a patchElem.

I haven't even managed to figured out if it's something in halogen-vdom or the driver code in this library that is the problem yet.

That's a pretty incomplete/confusing description most likely, but I'm just writing this for my benefit as much as anything else at this point in case something jumps out at me that I've not previously thought of.

This appears to also happen with the Real World Halogen example: click New Post and immediately click Home (without having selected an input field or something) results in the home page being rendered in a div below the New Post form.

This does NOT happen when an input field is clicked, before clicking Home. Also when an existing post is edited this does not happen.

(I've added some debug logging to the example code and it appears that the problem does not occur when Receive in the Editor component is/has been called before Home is entered; which may be totally unrelated).

garyb commented

Yeah, Real World Halogen uses halogen-store which does things that will trigger this situation.