Very weird behavior. On pointerDown
, a component transacts and re-renders itself under some condition. When the re-render happens, no click
event is triggered (not its own, not from any of its children components (they don't even re-render)), but pointerUp
events are all triggered as expected. Logging looks like this: pointerDown -> render -> pointerUp -> click not triggered
I've already spent a few hours on this and unless I am doing something terribly wrong, it almost looks like a bug.
@jatkin Right, good lead but it doesn't seem to be the issue. The weirdness would remain anyways since then it would be expected that onPointerUp
or onMouseUp
would bizarrely not be fired either.
@cjmurphy I see what you mean but lambdas in children are created solely based on their query, they don't need anything from the parent.
The plot thickens.
Still good to turn the brain off and always transact 'anything that might be triggered at the child level but apply to all children' from the parent. Good to do that regardless of any theory. Your problem is related to 're-ordering children'.
Can 'under some condition' be done in a mutation? So both "up" and "down" both simply call a mutation.
Ok so I think I have slightly narrowed it down. It is not exactly the rendering after `down` that seems to be the problem. It is the mutation itself (any other one does not cause this problem).
The component in question is generated from a vector of such components. What the down
mutation does is ensures that it becomes last in the vector so it is rendered last. This problem happens only when the reordering happens (my 'condition', if not last, make it so). Yes, :key
is properly used as it should.
It is as if reordering children on down
cancels all immediate click
events in those children. What is really puzzling is that immediate up
events trigger just fine, proving that a click indeed happened.
I'm afraid I don't know anything about 'generating a component from a vector of components'. To me defsc components are static things, composed together using get-query
. I know you can have dynamic queries but I've never needed that feature.
My bad, it was just a poor way of saying that a parent component joins on a list of those components. In other words, when a mutation reorders that list via down
on a child, click
is mysteriously not fired, but up
is.
When the mutation does not reorder the list, then the expected happens : down -> up -> click
To understand my own code better I have two functions called get-query1
and get-query*
, but they are both just get-query
. You mean get-query*
, which ends up being a vector of idents in app state. And your mutation is re-ordering these idents within the vector.
Also I can't get my head around what 'click' is. You have an up button and a down button that fire their respective mutations. It sounds like you are expecting a mutation to fire a click. The only thing that mutations usually 'fire' are st->st functions.
onClick
which is fired after onPointerDown
and onPointerUp
(supposing all three are being used)
I would have click as a st->st function then. Have onPointerDown
and onPointerUp
each call one mutation. user event -> mutation -> st->st function.
st -> st ?
app state in and app state out. I'll find it in the docs...
They are functions that end in *, by convention.
Just search for * in the book
Right, but the point of those onClick
events is that its the standard thing to do. It has defined behavior.
I am experimenting and yes, there is something weird about reordering children at onPointerDown
or onMouseDown
which prevents onClick
events from firing.
My previous post seems to be a general problem so I'll try to reword it in general terms.
A parent joins on a list of children. Each child registers a onMouseDown
, a onMouseUp
and an onClick
event. A click on a child will fire those events in that order, as expected.
BUT. In the case where onMouseDown
reorders that list of children via a mutation, inducing a re-render before other events are processed, onClick
is mysteriously NOT fired. However, onMouseUp
fires as expected. This is weird because the definition of a click is exactly that, mouse or pointer going down and up on the same element. Furthermore, the dom elements don't even move (position: absolute). Nothing mysteriously unmounts/remounts.
Re-rendering right after onMouseDown
and before other events is not the problem. Reordering the list is.
Same happens with onPointerDown
and onPointerUp
. Children are properly keyed, React does not complain.
all sounds very frustrating! did you try to use a ref and see if it changes somehow? Do you do anything to the event in the onMouseUp? E.g. preventDefault/stopPropagation?
Indeed it is! The ref does not seem to change and I am 100% positive there is no preventDefault
or stopPropagation
...
happens across all browsers? I guess it sounds like a react/DOM bug.
Oh right dom events. Should be possible to determine one event for one user operation. onClick means mouse has been pressed and released. Funny to have events for both onMouseDown and onClick. I'd want to avoid getting into that situation in the first place 😜
After some experimentation, I have rephrased the problem in my last post. Seems to be a general one. Hopefully it is more understandable.
Can you stick to either Pointer
or Mouse
events and not combine them? I'd never heard of the Pointer
events till now.
Unfortunately it doesn't change anything
onClick doesn't happen when you do something in mouse down. Is that the problem?
onMouseDown
And you can't avoid needing to use onClick?
It would mean emulating onClick in a lot of places which would only show how shitty, truly shitty, web programming is 😛
If you are doing something in onMouseDown and something else in onMouseUp, then there is no need to have onClick. Whatever you are doing in onClick can be done in onMouseUp.
Not so much a Fulcro problem but an event bubbling (whatever) problem.
Might be a Fulcro problem maybe due to the mutation system? But could just as well be a problem with React
Can you get the same behaviour with just printing messages, not doing any transacts at all?
Nope, my last post explains this better (I hope)
But in practical terms onClick can always be avoided if you use onMouseUp when only need 'click' functionality, and both onMouseUp and onMouseDown when doing something more involved that needs them both.
Yep, but using onMouseUp instead of a proper click can sometimes result in poor UI behavior. I'll hack something else meanwhile. Heck, the DOM is just one big hack anyway...
Can you have the function that accepts the event (for onMouseDown) be passed in from the parent? So when (transact this ...)
, the this
is that of the parent?
Any mutation on children should always be transacted from the parent.
I'm really reaching here, but could this be related? https://book.fulcrologic.com#_callbacks_causing_over_rendering
Unfortunately no, those children don't actually need anything from the parent, their query suffice. The parent is a singleton easy to find.
I don't think they are the same... If you have component A, and A re-renders to the dom, and A includes lambdas, those lambdas could be changing out of under you b/c they don't compare =. Not sure if that would change anything though, because the behavior of both lambdas should* be the same.
@adam678 Are you using computed to bring any functions that call mutations that affect many children in from the parent? I want to rule that out as an issue.