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

ref methods not working when using dynamic import with nextjs

Open singh-inder opened this issue 3 years ago • 8 comments

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

  1. 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

singh-inder avatar May 15 '22 03:05 singh-inder

Same issue here. I'm using useRef to access ReactPlayer, and somehow it's returing retry() instead of any other instance methods.

LuLue7775 avatar May 31 '22 11:05 LuLue7775

Can anybody share a codesandbox Or stackblitz link would be helpful to work ok this issue.

b4s36t4 avatar Jun 02 '22 10:06 b4s36t4

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

minhtc avatar Jun 02 '22 10:06 minhtc

why not use forwardRef here?

davidkhierl avatar Jun 30 '22 11:06 davidkhierl

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.

Multiply avatar Jul 13 '22 07:07 Multiply

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

}

singh-inder avatar Aug 06 '22 05:08 singh-inder

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: ƒ ()

geminiyellow avatar Apr 27 '23 09:04 geminiyellow

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

vasabigreencolor avatar May 26 '23 08:05 vasabigreencolor