Open davidkhierl opened 2 years ago
We got around this by effectively memoizing a boolean to track the loading state of it (and only rendering it once).
I‘d recommend to check on something like window (which is only available on client side). This needs to be done in useEffect for proper handling. Then you simply conditionally display the player.
hasWindow && <ReactPlayer …/>
Like @sandrooco said, this can fix the issue. Just a small component to show the full picture
@davidkhierl Dynamically import the react-player to remove this error. This fixed the error for me. No need to check for window object.
import dynamic from "next/dynamic";
const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
Make sure to implement this solution when using the above method ref methods with dynamic imports
These workarounds look good. It’s also possible this is fixed in react@18.1.0
and react-dom@18.1.0
Um sorry, why this issue closed? I'm still getting hydration error with react@18.1.0
, react-dom@18.1.0
, next@12.6.0
.
Dynamic import fixed the issue, but the onProgress
props isn't working.
@degitgitagitya It seems to be a issue with react-player@2.10.1
. I downgraded to 2.10.0
and onProgress
worked again.
I tested with react@18.1.0
, react-dom@18.1.0
, next@12.1.6
Rendering the component on the client side only isn't a solution and has negative performance impact, @cookpete this issue should be reopened.
Rendering the component on the client side only isn't a solution
@mrgnou I’m happy to reopen this for visibility (although there is quite a backlog of issues now and I have little spare time) but what is the solution? What should be rendered on the server? This library loads third party scripts on the client to embed video players. What markup could we possibly render on the server that would make sense?
Is it an alternative is to include a empty iframe ? I suppose iframes are a good solution as they could be marked optionaly as unoptimized. Or maybe it could include a option for client-only, where it waits of an effect to set a boolean true if window is defined, it does defeat the pourpouse of optimization, but makes a transparent workaround for some providers. (I'm saying thins whithout a look at source code)
Rendering the component on the client side only isn't a solution
@mrgnou I’m happy to reopen this for visibility (although there is quite a backlog of issues now and I have little spare time) but what is the solution? What should be rendered on the server? This library loads third party scripts on the client to embed video players. What markup could we possibly render on the server that would make sense?
I'd say everything that can be rendered synchronously to avoid client side rerender.
I know maintaining such a lib is really time consuming, and thank you for your hard work so far, there ain't many lightweight react players out there!
Seems like this should work in light
mode at least, but it doesn't, suggesting that the issue is not just third-party scripts. In any case, those would normally be loaded after hydration, no? If nothing can be rendered server-side in some cases, I think that's fine, but it would be useful for the README to at least spell this out in the implementation directions rather than not.
'use client'
import { useState, useEffect } from 'react'
export default function App() {
const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
return {isClient ? <ReactPlayer /> : <p>The video player cannot render on the server side</p>}
}
'use client' import { useState, useEffect } from 'react' export default function App() { const [isClient, setIsClient] = useState(false) useEffect(() => { setIsClient(true) }, []) return {isClient ? <ReactPlayer /> : <p>The video player cannot render on the server side</p>} }
This worked for me in next 14. Thanks!
Solution tweak that worked on this end: return null
, not html:
'use client' // if using app dir
import { useState, useEffect } from 'react'
export default function App() {
const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
return {isClient ? <ReactPlayer /> : null}
}
Solution tweak that worked on this end: return
null
, not html:'use client' // if using app dir import { useState, useEffect } from 'react' export default function App() { const [isClient, setIsClient] = useState(false) useEffect(() => { setIsClient(true) }, []) return {isClient ? <ReactPlayer /> : null} }
Yes this fixes the hydration but ref won't work and other callback props like onProgress
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
Thanks Sir its Working Now.
The hydration error remains when using the canary v3.0.0 and the React 19 Release Candidate 😢 Do we have to use ReactPlayer's fallback
prop and set it to false? The fallback
prop has a ReactElement
type, not ReactElement | false
?
Current Behavior
causing error: Hydration failed because the initial UI does not match what was rendered on the server.
Expected Behavior
should not cause error
Steps to Reproduce