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