react-player
                                
                                 react-player copied to clipboard
                                
                                    react-player copied to clipboard
                            
                            
                            
                        Error: Super expression must either be null or a function on NextJS 13
Current Behavior
i just wrote one line of code like the one in the example. Then I got an error like the issue title
Expected Behavior
No errors
Steps to Reproduce
- Import ReactPlayer
- <ReactPlayer url={youtubeURL} />
- npm run dev
Environment
- URL attempting to play: localhost
- Browser: edge
- Operating system: windows 10
- jsFiddle example: -
- framework: NextJS 13 using appdirectory
Other Information
@feri-irawan Are you instantiating the component in a "use client" component? Doing that solves the issue for me but I run into hydration issues shortly.
Adding the 'use client' directive at the top of the file solves the initial error and produces a new one, as mentioned by @lundjrl, regarding the component’s hydration.
By utilizing the useEffekt() hook I managed to get external sources to work properly (tested for YouTube and Vimeo):
import { useEffect, useState } from 'react'
import ReactPlayer from 'react-player'
export default function Figure({ video }) {
  const [isLoaded, setIsLoaded] = useState(false)
  useEffect(() => {
    setIsLoaded(true)
  }, [])
  return(
    {isLoaded ? (
      <ReactPlayer
        url={video?.source}
      />
    ) : null}
  )
}
But when the url prop is sourced from /public or a CDN (like Sanity) then the <video> element’s src attribute remains undefined. Any ideas on why this could be happening?
@sebastianhaiss Thank you, this helped.
Adding the
'use client'directive at the top of the file solves the initial error and produces a new one, as mentioned by @lundjrl, regarding the component’s hydration.By utilizing the useEffekt() hook I managed to get external sources to work properly (tested for YouTube and Vimeo):
import { useEffect, useState } from 'react' import ReactPlayer from 'react-player' export default function Figure({ video }) { const [isLoaded, setIsLoaded] = useState(false) useEffect(() => { setIsLoaded(true) }, []) return( {isLoaded ? ( <ReactPlayer url={video?.source} /> ) : null} ) }But when the
urlprop is sourced from /public or a CDN (like Sanity) then the<video>element’ssrcattribute remains undefined. Any ideas on why this could be happening?
It works for me :)
'use client'
import Image from 'next/image';
import styles from '../.././Page.module.css';
import data from '../.././data.json';
import Navbar from '../.././components/Navbar';
import Link from 'next/link';
import ReactPlayer from 'react-player'
import { useState, useEffect } from 'react';
export default function Page({ params }) {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    setIsLoaded(true)
  }, [])
  return (
    <div>
      <Navbar />
      <h1
        className='text-7xl text-center tracking-tighter font-extrabold mb-14 mt-10'
        id={styles.heading}
      >
        VideoCourse
      </h1>
      <div className='flex items-center place-content-evenly flex-wrap'>
        {data[params.course - 1]['video_links'].map((video, index) => (
          <div className='flex flex-col mb-10 items-center border-2 cursor-pointer hover:border-zinc-300 solid h-96 w-80 border-zinc-700 rounded-xl' key={index + 1}>
            {isLoaded ? (
              <ReactPlayer
                url={video?video:null}
              />
            ) : null}
          </div>
        ))}
      </div>
    </div>
  );
}
this works for me
An alternative, debatably cleaner approach is to wrap react player in its own 'use client' component. I'm new to server components (maybe everyone is?) and co-workers keep pointing me to this route. One wrote this decent post on the subject.
player.js
'use client';
import ReactPlayer from 'react-player';
export default (props) => {
  return <ReactPlayer {...props} />;
};
other file
import Player from 'player.js';
...
<Player url="..." />
Rather than using state, this seems to be a good case to use next's dynamic so it's using suspense:
const ReactPlayer = dynamic(() => import('react-player/file').then((ReactPlayer) => ReactPlayer), {
  ssr: false,
})
type VideoPlayerProps = FilePlayerProps & {
  className?: string
}
export const VideoPlayer = ({ className, ...rest }: VideoPlayerProps) => {
  return (
    <div className={twMerge('aspect-video', className)}>
      <ReactPlayer width="100%" height="100%" {...rest} />
    </div>
  )
}