useLayourEffect if used on a server generates following warning useLayoutEffect does nothing on the server, because it...
useEffect is just noop without warning
There are other lifecyles methods available in React which are not worked on the server and as developers we know about.
Would you mind to remove it and change on noop as like as useEffect or there some deep reason to have it.
I think the idea is that unlike useEffect, useLayoutEffect is used for things that affect initial render. For example measuring a tooltip and then changing its position. When you write code like this but later want to add server rendering, you experience a problem: the server rendered HTML doesn't have the useLayoutEffect change applied until it hydrates. So the user sees a broken intermediate state.
This warning is meant to discourage you from writing code that appears to work on a client-only render, but looks "broken" until hydration on SSR render.
I think the idea behind this warning is that you need to always make a decision:
Either this should have been useEffect rather than useLayoutEffect. That would explicitly indicate initial render isn't meant to be blocked by running the effect. So it's fine to show the intermediate state.
Or the component shouldn't have been server rendered. Such as a tooltip being rendered by mistake.
There are probably cases that fall outside of these recommendations. I'd like to hear more about the practical cases where you feel either of these alternatives is insufficient.
I'd say anything, that can be enhanced by javascript, but is ok and should be shown, without it.
An example could be to VanillaTilt something in the client, but the content per se should already be in the ssrd html. This is a good example, as it would not look broken, it would just behave "broken" (as in not behave at all).
For something rendered on the server useEffect and useLayoutEffect are initially not that different. The first one will kick in eventually, so will useLayoutEffect only after the script is loaded and executed.
But later on, if I add more of these components dynamically, there is a difference.
As it is a warning, which only happens on dev builds (does this hold true for ssr too?), I'd probably leave that in, but maybe limit it to be reported once?
If someone really hates the warning, there is still the option to replace it yourself by a noop,
cc @sebmarkbage who's thought about this more and has a particular vision around how it should work.
There is case there LayoutEffect is not used for initial rendering sync
In my case LayoutEffect is used for some kind of TransitionGroup animation. In no case it's used for Layout or anything similar and the reason I use LayoutEffect is better to show in example:
https://codesandbox.io/s/n0vj63njjm
See if you use just useEffect after click on OK you will get result 1, if you will use synchronous useLayoutEffect you will get 2
This is caused by that fact that events executed not inside React event handlers are not batched (and TransitionGroup uses some-kind of setTimeout event to not close the items for some period).
So in my case if 2 items synchronously get event to remove, one remove lost like in example above. So synchronous nature of useLayoutEffect can be used to solve some problems like this.
Having that event batching is not documented this solves the problem in consistent way.
PS:
Thank you for answer @gaearon , I just revisited my code, and found that I overused useLayoutEffect even in places there it has no sense, so except example above all warnings said me true, I'm able to use just useEffect.
@istarkov I believe that pattern will break with concurrent mode React and inside batched updates since React isn't going to synchronously flush the "forceUpdate". So it's already a discouraged pattern. Do you have some richer example that might illustrate the problem?
One problem is that ref resolution (when it's passed to a DOM node) in React isn't consistent with the useEffect life-cycle which is a pretty bad design that we know we want to look into separately - before actually finalizing Hooks in a public release.
I suspect there might be problems with this warning because useLayoutEffect have to be unconditional but it might only really get used for updates and then it should be ok but there's no way for us to tell that it's only really used for updates. The alternative is to hoist it out into a separate component but that's a pretty big hammer if the code is compliant anyway.
Another case where it might be ok is if this component is part of a "hidden" subtree. Not sure it makes sense to server render a hidden subtree at all though.
I think we need to see more actual legit use cases to see how/if we could narrow this warning a bit but so far I haven't seen/thought of any.
Ok I see, the pattern above will be fine with batching see example with batching https://codesandbox.io/s/lpp89ql0ym
It's current issue is the lack of officially documented batching ;-) BTW yes the code like this smells, so I'll better rethink it.
Thank you for the answers. I'll close this.
@sebmarkbage @gaearon not sure if this is a better use-case but since it brought me to this issue I figured I'd describe my situation here
I'm creating a cross-platform app with react-native-web using server rendering. My problem is that layout/dimension props are undefined in the server (and I can't use media queries), so the styles that rely on them are rendered incorrectly until after they're updated with the correct window/screen properties.
I figured useLayoutEffect would help solve this?
the solution I'm using for now is cloaking my site until after the components that rely on window/screen props have been updated, but I'd like to move away from this if there is an alternative
There is a very valid use case for getting rid of this warning. I needed to render react components to a string in the browser for use outside the react DOM space in order to render (mostly cached) React components inside a third party component written in plain javascript (ag-grid). I was able to get rid of these really annoying warnings by writing my own babel plugin to strip them out, but would be great to have a way to configure these.
Most helpful comment
There is a very valid use case for getting rid of this warning. I needed to render react components to a string in the browser for use outside the react DOM space in order to render (mostly cached) React components inside a third party component written in plain javascript (ag-grid). I was able to get rid of these really annoying warnings by writing my own babel plugin to strip them out, but would be great to have a way to configure these.