useLayoutEffect and useEffect odd behavior
hey @localvoid think i found a bug?
i'd like to use useLayoutEffect to measure the rendered DOM. i expcted it to fire once the DOM has been flushed/synced. but it fires before anything is rendered.
useLayoutEffect(c, () => {
console.log('useLayoutEffect!');
})();
however, if i add a useEffect above it, then the useEffect fires after the DOM has been flushed/synced, then useLayoutEffect also fires.
useEffect(c, () => {
console.log('useEffect!');
})();
useLayoutEffect(c, () => {
console.log('useLayoutEffect!');
})();
- i did not expect useLayoutEffect to fire before DOM sync
- i did not expect useEffect to affect useLayoutEffect
actually it looks like the DevTools and paint behavior is weird. if i stick a breakpoint into the useEffect, i see the dom painted once it lands there, but if i only stick a breakpoint into useLayoutEffect, then it is not painted by the time it gets there, but the dom is still present and queryable.
i guess it's not too clear if these helpers follow React convention, where useEffect fires async after useLayoutEffect, which fires first and before paint so you can query/affect the DOM. so the ordering of these is a bit unusual, but maybe not problematic in my case.
it would be helpful to provide an example where using the wrong effect would be problematic.
i guess it's not too clear if these helpers follow React convention
No, they don't follow the React convention. useEffect() hooks are fired immediately after rendering/updating root subtree is finished to make sure that any DOM modification are applied before reading from DOM and useLayoutEffect() hooks are fired on animation frame. I guess, I should have chosen different names to avoid confusion. If it doesn't follow this behavior, it is probably a bug.
Originally, ivi had a much more complicated scheduler to deal with ((write|read)+|after)+ batching until DOM updates are stabilized, but I didn't encountered any use cases that required such complex scheduling, so I've decided to make it as simple as possible. So the idea was that useEffect() is a hook that should apply DOM mutations(write) side effects immediately after "declarative" updates are finished, then "layout" effects are triggered on rAF to read from DOM and if something is changed during layout effect, it should invalidate affected components and they will be updated during the next microtask.