react-player icon indicating copy to clipboard operation
react-player copied to clipboard

React 18 NextJS 12.1 - Hydration failed

Open davidkhierl opened this issue 3 years ago • 20 comments

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

  1. Fresh install nextjs app, will install react 18 by default
  2. include ReactPlayer component

davidkhierl avatar Mar 30 '22 08:03 davidkhierl

We got around this by effectively memoizing a boolean to track the loading state of it (and only rendering it once).

JulianLeviston avatar Apr 01 '22 02:04 JulianLeviston

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 …/>

sandrooco avatar Apr 01 '22 05:04 sandrooco

Like @sandrooco said, this can fix the issue. Just a small component to show the full picture

video_player_component

Dovalization avatar Apr 07 '22 17:04 Dovalization

@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

singh-inder avatar Apr 24 '22 19:04 singh-inder

These workarounds look good. It’s also possible this is fixed in [email protected] and [email protected]

cookpete avatar May 02 '22 22:05 cookpete

Um sorry, why this issue closed? I'm still getting hydration error with [email protected] , [email protected] , [email protected].

Dynamic import fixed the issue, but the onProgress props isn't working.

degitgitagitya avatar May 12 '22 06:05 degitgitagitya

@degitgitagitya It seems to be a issue with [email protected]. I downgraded to 2.10.0 and onProgress worked again. I tested with [email protected] , [email protected] , [email protected]

#1453

singh-inder avatar May 13 '22 07:05 singh-inder

Rendering the component on the client side only isn't a solution and has negative performance impact, @cookpete this issue should be reopened.

leo-cheron avatar Jun 05 '22 14:06 leo-cheron

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?

cookpete avatar Sep 19 '22 21:09 cookpete

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)

MuMaestro avatar Oct 24 '22 16:10 MuMaestro

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.

  • Concerning native html player: pretty much everything.
  • Concerning embedded players: iframe with prefilled attributes if light mode isn't set to true.

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!

leo-cheron avatar Nov 20 '22 16:11 leo-cheron

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.

coreyward avatar Feb 16 '23 18:02 coreyward

Solution in the Next.js doc

'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>}
}

KelvinQiu802 avatar Jan 18 '24 14:01 KelvinQiu802

Solution in the Next.js doc

'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!

qbounti avatar Jan 31 '24 07:01 qbounti

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}
}

christopher-theagen avatar Mar 04 '24 14:03 christopher-theagen

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

davidkhierl avatar Mar 04 '24 16:03 davidkhierl

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

luwes avatar Apr 19 '24 16:04 luwes

Thanks Sir its Working Now.

nitesh-lab avatar May 10 '24 11:05 nitesh-lab