使用 nextjs、react 和 flowplayer 取消 eventListeners 的正确方法

时间:2021-04-08 17:33:25

标签: javascript reactjs next.js flowplayer

我目前在 nextJS 项目中使用 TypeScript。我使用的是 CDN 版本的 flowplayer,通过钩子添加到页面中。

我在组件的全局范围内有一个变量:视频。

我正在使用 useScript 钩子来加载它。 - https://usehooks.com/useScript/

 const status = useScript(
   '//cdn.flowplayer.com/players/433ff492-dbea-4527-9f9f-6dd08bc3b0be/native/flowplayer.async.js',
 );

当状态变为就绪时,此效果被激活:

useEffect(() => {
function renderFlowPlayer() {
  window.flowplayer?.cloud?.then(() => {
    video = window.flowplayer('#flowplayer');
    video.on('pause playing timeupdate ended', stateHandler);
    console.log(video);
  });
}
renderFlowPlayer();
return () => {
  if (video) {
    video.off('pause', stateHandler);
    video.off('playing', stateHandler);
    video.off('timeupdate', stateHandler);
    video.off('ended', stateHandler);
    video.destroy();
  }
 };
}, [status === 'ready]);

flowplayer.cloud.then 在脚本准备好后被添加到 window 对象中。

这是我的 stateHandler 函数:

function stateHandler(ev) {
if (ev.type === 'pause') { console.log('paused'); }
if (ev.type === 'playing') { console.log(`Playing at ${event.target.currentTime}, duration is: 
${event.target.duration}, video ID is: ${event.target.opts.metadata.id}`); }
if (ev.type === 'timeupdate') { console.log(event.target.currentTime); }
if (ev.type === 'ended') { console.log('The end'); }

所有console.log 调用首先正确打印值,但是如果我转到另一页并返回,则所有内容都会重复打印。 我猜这些事件监听器没有被正确杀死。 当组件即将卸载时,删除所有这些侦听器的正确方法是什么?

提前致谢!

组件的完整代码如下:

import React, { useState, useEffect } from 'react';
import useScript from '@components/customHooks/useScript';

const SOURCES = ['b8302bc5-0f5f-4de6-a56e-6c05a9cd6025', '03513ba8-ea10-4c41-8f0b-82ab134b995c'];

let video = null;

export default function FlowPlayerWrapper() {
  const [demoSrc, setDemoSrc] = useState(SOURCES[0]);

  const status = useScript(
    '//cdn.flowplayer.com/players/433ff492-dbea-4527-9f9f-6dd08bc3b0be/native/flowplayer.async.js',
  );

  function stateHandler(ev : FlowPlayerEvent) {
    const Event = ev.target;
    if (ev.type === 'pause') { console.log('pausado'); }
    if (ev.type === 'playing') { console.log(`Tocando em ${Event.currentTime} e a duração é: ${Event.duration} e o id do vídeo: ${Event.opts.metadata.id}`); }
    if (ev.type === 'timeupdate') { console.log(Event.currentTime); }
    if (ev.type === 'ended') { console.log('Fim'); }
  }

  useEffect(() => {
    function renderFlowPlayer() {
      window.flowplayer?.cloud?.then(() => {
        video = window.flowplayer('#flowplayer');
        video.setSrc(demoSrc);
        video.on('pause playing timeupdate ended', stateHandler);
        console.log(video);
      });
    }
    renderFlowPlayer();
    return () => {
      if (video) {
        video.off('pause', stateHandler);
        video.off('playing', stateHandler);
        video.off('timeupdate', stateHandler);
        video.off('ended', stateHandler);
        video.destroy();
      }
    };
  }, [status === 'ready']);

  const togglePlay = () => {
    if (!video) return;
    video.togglePlay();
  };

  const toggleSrc = () => {
    if (!video) return;
    const nextIndex = SOURCES.indexOf(demoSrc) + 1;
    video.setSrc(SOURCES[nextIndex] || SOURCES[0]);
  };

  const toggleMute = () => {
    if (!video) return;
    video.toggleMute();
  };

  const toggleExtra = () => {
    if (!video) return;
    video.currentTime += 20;
  };

  const toggleFullScreen = () => {
    if (!video) return;
    video.toggleFullScreen();
  };

  return (
    <div>
      <div>
        Script status:
        {' '}
        <b>{status}</b>
      </div>
      <div id="flowplayer" data-player-id="afe735a8-5e21-4f91-9645-1ca2a6f4541d" />
      <div className="row">
        <div className="column">
          <h2>Chamadas API</h2>
          <button type="button" onClick={togglePlay}>Tocar / Pausar</button>
          <button type="button" onClick={toggleMute}>Mute / Unmute</button>
          <button type="button" onClick={toggleExtra}>Acrescentar 20s</button>
          <button type="button" onClick={toggleFullScreen}>Full screen</button>
          <button type="button" onClick={toggleSrc}>Mudar vídeo</button>
        </div>
      </div>
    </div>
  );
}

1 个答案:

答案 0 :(得分:1)

我已经用这个钩子修复了它:

 useEffect(() => {
    function renderFlowPlayer() {
      // Função que está disponível após o script estar carregado e executando
      window.flowplayer?.cloud?.then(() => {
        video = window.flowplayer('#flowplayer');
        // id do video é settado na próxima linha
        video.setSrc(demoSrc);
        video.on('pause playing timeupdate ended', stateHandler);
      });
    }
    if (isInitialMount.current) {
      isInitialMount.current = false;
    } else {
      renderFlowPlayer();
    }

    return () => {
      if (video) {
        video.off('pause', stateHandler);
        video.off('playing', stateHandler);
        video.off('timeupdate', stateHandler);
        video.off('ended', stateHandler);
        video.destroy();
      }
     };
    }, [status === 'ready']);

仅在状态就绪时运行效果,而不是在安装阶段完成时运行。 https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables