Search code examples
reactjsuse-effectuse-refdynamic-import

Dynamic import in useEffect causes constructor to be called twice


I'm dynamically importing @vimeo/player in useEffect but when setting up Player I'm getting Uncaught (in promise) TypeError: You must pass either a valid element or a valid id. which comes from this part in the Vimeo script:

if (!isDomElement(element)) {
  throw new TypeError('You must pass either a valid element or a valid id.');
}     } // Already initialized an embed in this div, so grab the iframe

So I guess the new Player constructor is called twice for some reason? This error does not appear when I use a normal import - even though it seems setup is called twice no matter if dynamic import or not so I'm a bit confused why this error only appears with the dynamic import. I tried adding a cleanup function but that also doesn't help - grateful for any pointers!

useEffect(() => {
    let isSetup = false;
    async function setup() {
        if (!isSetup) {
            const { default: Player } =  await import('@vimeo/player');
            playerRef.current = new Player(
                playerRef.current,
                playerConfig,
            );
            isSetup = true;
            playerRef.current.on('loaded', () => setIsLoading(false));
        }
    }


    if (playerRef.current) {
        setup();
    }

    return () => {
        isSetup = false;
        playerRef.current.destroy();
    };
}, [playerRef]);

Solution

  • I don't think any import is causing the issue.

    I suggest removing the useEffect hook, because it should only be executed when the playerRef changes right? So you can port your code into a useCallback.

    import { useCallback} from 'react';
    
    // Open component
    // ...
      const onPlayerRefChange = useCallback((node) => {
        // Insert your code here and `node` will be the mounted html element
     )};
    // ...
    // Close component
    

    In your jsx use the ref attribute like this:

     <div ref={onPlayerRefChange}></div>
    

    This wat the onPlayerRefChange function will only be called when the ref changes (should be 1 time if not the element changes multiple times and there is another bug in your code).

    I'm not sure what the use for isSetup is, but if you want to use that I suggest moving it in a useState.