ref methods not working when using dynamic import with nextjs
Current code=>
import dynamic from "next/dynamic";
const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
<ReactPlayer
config={config}
ref={player}
width="100%"
height="600px"
url="//vjs.zencdn.net/v/oceans.mp4"
muted={true}
playing={playing}
controls={true}
onProgress={}
/>
Current Behavior
Ref methods like player.current.getCurrentTime(); are not working when using dynamic imports with nextjs. Whenever I use methods which are available by assigning ref, I get this error
TypeError: player.current.getCurrentTime is not a function
Expected Behavior
expecting ref methods to work.
Steps to Reproduce
- Nextjs app with
[email protected],[email protected],[email protected]and[email protected]. I've already tested with[email protected]. Not working in that version as well.
Environment
- Browser: Chrome
Same issue here. I'm using useRef to access ReactPlayer, and somehow it's returing retry() instead of any other instance methods.
Can anybody share a codesandbox Or stackblitz link would be helpful to work ok this issue.
This issue is related to dynamic import behaviour instead of react-player package. You can simply wrap the ReactPlayer in a custom component then use a custom props to pass the player ref to parent. Example: ReactPlayerWrapper.tsx
import {LegacyRef} from 'react'
import ReactPlayer, {ReactPlayerProps} from 'react-player/lazy'
export default function ReactPlayerWrapper(
props: ReactPlayerProps & {
playerRef: LegacyRef<ReactPlayer>
},
) {
return <ReactPlayer ref={props.playerRef} {...props} />
}
why not use forwardRef here?
We're having the same issue at our end as well.
Opting out of lazy loading is not an option due to the size of the library, and the solutions above doesn't seem to address it correctly.
I'll be happy to test any other proposals, if there are any.
The only solution so far is to wrap the player in another component and import that component. Then we can use dynamic imports and the ref methods work as expected.
// components/VideoPlayer.js
import ReactPlayer from "react-player/lazy";
function VideoPlayer({ playerRef }) {
return (
<ReactPlayer
ref={playerRef}
muted
playing
controls
/>
);
}
// pages/index.js
import dynamic from "next/dynamic";
const VideoPlayer = dynamic(() => import("../components/VideoPlayer"), {ssr: false});
function Home(){
const playerRef=useRef();
return <VideoPlayer playerRef={playerRef} />
}
UPDATE: sorry, i should post it in next not here.
The only solution so far is to wrap the player in another component and import that component.
some plant to fix it?
i tried it but still only retry in current
// components/Chart.ts
import React from 'react'
export const Chart = ({ ref }: any) => <div ref={ref}>Chart</div>
Chart.displayName = 'Chart'
export default Chart
// TrendCharts.ts
const Chart = dynamic(() => import('@material/Chart'), { ssr: false })
export const TrendCharts: FC<any> = (props) => {
const $ref = useRef(null)
useEffect(() => { console.log($ref) }, [$ref])
return (<Chart ref={$ref} ... />)
}
the output is
{current: {…}}
current:
retry: ƒ ()
this is due to the fact that the word ref is reserved by the react itself and apparently the developers didn’t think about this moment, so with a dynamic improte for the ref you need to create a wrapper with the forwardedRef prop and in turn pass it as a normal prop
import React, { RefObject } from 'react'
import AppModal, { IAppModalProps, IAppModalRef } from '.'
export interface IDynamicAppModalProps extends IAppModalProps {
forwardedRef?: RefObject<IAppModalRef>
}
const DynamicAppModal: React.FC<IDynamicAppModalProps> = (props) => {
const { forwardedRef, ...args } = props
return <AppModal ref={forwardedRef} {...args} />
}
export default DynamicAppModal