React hooks,当组件卸载时如何触发一些逻辑

问题描述 投票:1回答:1

我现在正在玩钩子。我的代码看起来像这样:

    import React, { Fragment, useState, useEffect, useRef } from 'react';
import ReactPlayer from 'react-player';

import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

const VideoItem = () => {
  const [ playingStatus, setPlayingStatus ] = useState(false);
  const [ videoId ] = useState(318298217);
  const [ videoProgress, setVideoProgress ] = useState(0);
  const player = useRef();

  useEffect(() => {
    window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
    );

    return () => {
      window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
      );
      saveStateToLocalStorage(); // this needs to be fired only once when component onmounts but clearing effect is done every time videoProgress changes
    };
  }, [videoProgress]);

  const onVideoEnd = () => {
    console.log('backend call - video end status');
  };

  const seekToPoint = () => {
    const videosData = storage.hasKey(STORAGE_VIDEOS_DATA_KEY) &&
      JSON.parse(storage.getItem(STORAGE_VIDEOS_DATA_KEY));
    const toReturnVideoPoint = videosData[videoId] || 0;

    player.current.seekTo(Number(toReturnVideoPoint));
  };

  const saveStateToLocalStorage = () => {
    const videosPlayedDuration = {
      [videoId]: videoProgress,
    };

    storage.setItem(STORAGE_VIDEOS_DATA_KEY, JSON.stringify(videosPlayedDuration));
  };

  return (
    <Fragment>
      <ReactPlayer
        ref={player}
        playing={playingStatus}
        url={`https://player.vimeo.com/video/${videoId}`}
        onPause={() => {
          saveStateToLocalStorage();
          setPlayingStatus(false);
        }}
        onEnded={onVideoEnd}
        onProgress={progress => setVideoProgress(progress.playedSeconds)}
      />
      <button onClick={() => {
        seekToPoint();
        setPlayingStatus(true);
      }}
      >
        GO BACK TO THE PREVIOUS POINT
      </button>
    </Fragment>
  );
};

export default VideoItem;

我希望仅在组件卸载时清除我的效果,而不是在videoProgress状态发生变化时每次组件都被重新渲染。我可以使用空数组而不是[ videoProgress ],但是videoProgress方法中的saveStateToLocalStorage将不会更新,并且onPause方法不会导致正确保存到localStorage(它将保存0)。有没有办法用钩子而不是使用componentWillUnmount生命周期的类组件?

reactjs
1个回答
2
投票

你必须了解useEffect的工作原理。

useEffect(() => {
    // your code
    return () => {
      // your clearup code 
    };
  }, [videoProgress]); // => This is the key point. It's called dependency

每当依赖变化时,反应重新运行useEffect。你的videoProgress值会在时间间隔后发生变化(可能在1秒之后,我不知道)。这就是为什么反应重新运行useEffect。

你可以这样做。

useEffect(() => {
    // your code
    return () => {
      // your clearup code. =>> This block will work as componentWillUnmount
    };
  }, []); // => No Dependency

或者您可以添加视频ID的依赖关系(根据您的要求)。


One Handy example

useEffect(() => {
    // This block (before the return) will act as componentDidMount
    return () => {
      // This block will work as componentWillUnmount
    };
  }, []); // => beacase of No Dependency

单面注意:您可以拥有多个useEffect。

© www.soinside.com 2019 - 2024. All rights reserved.