react-player: Next.JS / React 18 - Hydration Error
Current Behavior
Unless react-player
is loaded on the client-side using dynamic/no-ssr or useEffect, React will panic with a hydration error.
Expected Behavior
Use of SSR should not result in a hydration error.
Steps to Reproduce
- Using Next.JS, import
react-player
and follow typical implementation instructions. - Error
Other Information
There is a great thread on Stack Overflow here (https://stackoverflow.com/questions/71706064/react-18-hydration-failed-because-the-initial-ui-does-not-match-what-was-render) where devs list various solutions to related issues.
Examples:
react
andreact-dom
may need to be updated.- Wrapping tags improperly, such as
<div>
inside<p>
will cause the error. - Lazy modules need to be wrapped in
<Suspense>
.
Please check again these scenarios in the codebase. Thank you!
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 24
- Comments: 24 (2 by maintainers)
Commits related to this issue
- Render `react-player` only if the `window` exists (#837) đď¸ [Asana Task]() đ [Preview Link](https://react-components-git-{branch-slug}-hashicorp.vercel.app) --- <!-- Reminder: This is an ope... — committed to hashicorp/react-components by nandereck 2 years ago
- [docs] Fix hydration issue for Video component (#25072) # Why <!-- Please describe the motivation for this PR, and link to relevant GitHub issues, forums posts, or feature requests. --> Afte... — committed to expo/expo by amandeepmittal 8 months ago
- [docs] Fix hydration issue for Video component (#25072) # Why <!-- Please describe the motivation for this PR, and link to relevant GitHub issues, forums posts, or feature requests. --> Afte... — committed to expo/expo by amandeepmittal 8 months ago
I agree that ReactPlayer should be SSR-friendly out of the box, @cookpete what do you think?
For now, until that happens, another workaround is to lazy-load the player using Next.js dynamic imports, as mentioned by @inderrr in this comment:
Have you tried this?
Itâs basically checking the window.
For temporary solution you can downgrade react to 17.0.2 for example
Iâve tried this and of course it works! but this means rendering the react-player component on the client side so I need to render another thing ( like an image) on the server side. I wish the react-player would handle the SSR by itself
@panzacoder I appreciate the thought youâve put into this. Unfortunately I think weâre at the point where a proper solution is simply not worth the time and effort it would take â you might as well rewrite the library from scratch. I have been gradually rewriting this with typescript, hooks, storybook, etc, but getting time to work on it is tricky.
There is no way to avoid using
window
as the whole point of the component is to load third party scripts to play a givenurl
. There is nothing we can really render during SSR because we just donât know what markup will be rendered by these scripts. I guess we could usenoembed
to fetch a thumbnail and render that, but I donât know how intrusive that would be to the codebase. At this point I would much rather keep things simple considering how complex this library has become to satisfy such a wide range of developers/platforms.Some ideas:
lazy
andSuspense
should we just releasev3
with it removed completely, and just let the developer decide which players to include and how to lazy load them? The majority of users are only ever using one player, and more and more users are using a platform that has lazy loading built in, likenext/dynamic
.react-player
in a way that supports Next.js? So the changes in this library are minimal and we just push Next.js users towardsreact-player-next
(or whatever we call it).we have released a canary version that should resolve this issue in many cases. Suspense is enabled and more importantly the current playerâs root element is rendered on the server. please let me know if any issues arise. https://www.npmjs.com/package/react-player/v/3.0.0-canary.0
from https://github.com/cookpete/react-player/issues/1428, if above doesnât work, try
return {isClient ? <ReactPlayer /> : null}
Solution in the Next.js doc
works for me. thanks ! đ
For anything not Next⌠im presuming using loadable components would work a treat.
Ok you were definitely on to something with this and it took me some digging but I think I figured out why this is so incompatible with SSR.
There was one bit of magic that I noticed in the Readme that struck me as odd but I couldnât figure out why. For Youtube embeds, there is an example of the actual url of the YT video, not the embed url or the id of the video. In other implementations Iâve seen or done for YT embeds, typically there is some more configuration needed around stripping the embed id or specifying the poster image (for a âlightâ version) but this handled it.
In the line you references, we are returning null on the server side, since Suspense doesnât work server side pre- React 18. I think now we could probably set a flag or do a check for the React version to enable Suspense/lazy. But that just allows the code to attempt to run in SSR.
The next piece Iâve seen is the call to window in the file
Preview.js
, and this is where the magic with the youtube URL happens:https://github.com/cookpete/react-player/blob/662082a2f2edc863e8ca9cefdd7a3c88ad49ea0d/src/Preview.js#L42
Basically, if the url is for youtube and a poster image isnât provided, we are fetching a YT endpoint that provides some meta about the video, including a poster image uri and html for an iframe.
Iâm going to make an attempt to fix this in a universal way in a fork I made, but one big thought is on my mind: Should we be doing it this way?
I think there might be a solution that is right enough for all React environments, but ultimately if this component is handling a certain level of data fetching, it needs to have integrations with specific frameworks that can handle this in the way that it intends to do so. Since SSR and SSG is becoming the norm for react, my thoughts on a refactor would be some or all of the following:
If I can find time, I will try to experiment with some of these concepts, but would be interested in feedback from @cookpete on these thoughts also.
Thank you, just what I was looking for đ
Sounds great. I just donât have the time or knowledge to implement, test and document it.