使用挂钩无法看到方法帮助器函数中的状态

时间:2019-03-25 10:37:38

标签: reactjs react-hooks

我无法在正在使用的帮助器方法中看到更新后的状态。所有这些都在基于类的组件中工作,但是在使用钩子时似乎并不相同。查看我的评论。

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

import { VIMEO_URL } from '../../consts/urls';
import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

import './VideoItem.scss';


const VideoItem = ({ vimeoId }) => {
  useEffect(() => {
    window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
    );

    return () => {
      window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
      );

      saveStateToLocalStorage();
    };
  }, []);


  const [ videoProgress, setVideoProgress ] = useState(0);

  const saveStateToLocalStorage = () => {
    const videosPlayedDuration = {
      [vimeoId]: videoProgress, // here I'm not getting updated videoProgress state, only default value
    };

    // here I will save videosPlayedDuration to the storage
  };

  return createPortal(
    <div className="video-modal-background" onClick={onVideoClose}>
      <div className="video-modal-window">
        <ReactPlayer
          playing={true}
          url={VIMEO_URL + vimeoId}
          onProgress={videoProgress => setVideoProgress(videoProgress.playedSeconds)} // here I'm setting state
        />
      </div>
    </div>,
    document.getElementById('modal-root')
  );
};

export default VideoItem;

所以正如您所看到的,我正在尝试使用更新状态,但是我得到的只是默认状态0。

2 个答案:

答案 0 :(得分:1)

该问题是由于关闭引起的。由于效果仅在初始渲染上运行,因此侦听器持有saveStateToLocalStorage的引用,该引用仅在初始渲染时从其关闭获取状态值,因此更新后的值在其中不可见。

每当videoProgress状态更改时,您都需要删除并添加侦听器。为此,您可以将videoProgress作为第二个参数传递给useEffect

const VideoItem = ({ vimeoId }) => {
  const [ videoProgress, setVideoProgress ] = useState(0);
  useEffect(() => {
    window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
    );

    return () => {
      window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
      );

      saveStateToLocalStorage();
    };
  }, [videoProgress]);


   function saveStateToLocalStorage(){
    const videosPlayedDuration = {
      [vimeoId]: videoProgress, 
    };

   };

  return createPortal(
    <div className="video-modal-background" onClick={onVideoClose}>
      <div className="video-modal-window">
        <ReactPlayer
          playing={true}
          url={VIMEO_URL + vimeoId}
          onProgress={videoProgress => setVideoProgress(videoProgress.playedSeconds)} // here I'm setting state
        />
      </div>
    </div>,
    document.getElementById('modal-root')
  );
};

export default VideoItem; 

答案 1 :(得分:1)

如果您希望拥有componentWillUnmount的行为,请使用useRef访问监听器中的更新值:

   const [ videoProgress, setVideoProgress ] = useState(0);
   const videoProgressRef = useRef(videoProgress);
   useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

   function saveStateToLocalStorage(){
      const videosPlayedDuration = {
        [vimeoId]: videoProgressRef.current, 
      };
   }

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

    return () => {
      window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
      );

      saveStateToLocalStorage();
    };
  }, []);

如果仅在saveStateToLocalStorage内部使用useEffect,最好将其移至useEffect的回调中。这样就不会在每个渲染器上都重新创建它:

  useEffect(() => {
    function saveStateToLocalStorage(){
        const videosPlayedDuration = {
          [vimeoId]: videoProgressRef.current, 
        };
    }

    window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
    );

    return () => {
      window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
      );

      saveStateToLocalStorage();
    };
  }, []);