cookpete / react-player

A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
https://cookpete.github.io/react-player
MIT License
9.44k stars 1.15k forks source link

React 18 NextJS 12.1 - Hydration failed #1428

Open davidkhierl opened 2 years ago

davidkhierl commented 2 years ago

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
JulianLeviston commented 2 years ago

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

sandrooco commented 2 years ago

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

Dovalization commented 2 years ago

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

video_player_component

singh-inder commented 2 years ago

@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

cookpete commented 2 years ago

These workarounds look good. It’s also possible this is fixed in react@18.1.0 and react-dom@18.1.0

degitgitagitya commented 2 years ago

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.

singh-inder commented 2 years ago

@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

1453

leo-cheron commented 2 years ago

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

cookpete commented 2 years ago

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?

MuMaestro commented 2 years ago

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)

leo-cheron commented 2 years ago

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!

coreyward commented 1 year ago

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.

KelvinQiu802 commented 10 months ago

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>}
}
qbounti commented 10 months ago

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!

christopher-theagen commented 9 months ago

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}
}
davidkhierl commented 9 months ago

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

luwes commented 7 months ago

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

nitesh-lab commented 6 months ago

Thanks Sir its Working Now.

suuf commented 5 days ago

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?