craft.js
craft.js copied to clipboard
useNode - dom is always 1 change behind the actual dom element
Describe the bug
When getting dom
from useNode. The dom element from the hook is always 1 iteration behind the actual element on the page.
To Reproduce Set up a useNode hook with dom & style in 1 component
const {
style,
dom,
} = useNode((node) => ({
dom: node.dom,
style: node.data.props.style,
}))
set up a setProp
from useNode
in a different component. and set the width to 100
The dom.offsetWidth will be 0
if you. then run setProp with style.width set to 200
The dom.offsetWidth will be 100
if you. then run setProp with style.width set to 50
The dom.offsetWidth will be 200
It's always 1 iteration behind the real deal.
This is incredibly frustrating trying to build an outline onRender
component. as the size of my outline is always wrong, until a user hovers over the element.
Expected behavior I expect the dom element from useNode to be the actual element and have the same size/position as the element the user sees on the screen.
Screenshots If applicable, add screenshots to help explain your problem.
Initial size on first render is correct (width is set to 600 by default)
using setProp
I change the width to 400
Always 1 step behind the actual size :(
When I hover over the element, it fixes itself and corrects back to the right size.
The same problem can be observed in the landing page demo:
If you change the dimensions of something (from the side menu), the position of the "IndicatorDiv" is still at it's old height / position.

Until you hover the element and it updates.
Not sure if it's the same underlying cause, but a similar issue exists when resizing the page - the menu doesn't follow the DOM it's attached to.
See the following as an example:
I am experiencing an issue that is likely related. I have a User Component that maps a prop to render a list of components, i.e.
const MyUserComponent = ({ items }) => {
return (
<div>
{items.map((item) => (
<button>{item}</button>
))}
</div>
);
};
Initially, when the items
prop is empty, the indicator shows up properly for my component.
However, when I add an item in the items
prop, the dom
value returned from useNode
now seems to think the dom
of my User Component is a <button />
instead of the parent <div />
, as shown by the indicator in the screenshot below:
Not knowing the inner mechanics of craftjs, I have a hard time wrapping my head around why this is happening. To your observation @MarkLyck, I do see that even after deleting all items from the items
prop, useNode
still thinks the dom
is the last existing <button />
although that doesn't even exist in the actual DOM any more.