Не могу увидеть состояние внутри вспомогательной функции метода с помощью хуков - PullRequest
3 голосов
/ 25 марта 2019

Я не вижу обновленное состояние внутри вспомогательного метода, который я использую.Все они работали в компоненте на основе классов, но, похоже, это не то же самое при использовании хуков.Посмотрите мои комментарии.

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 ]

1 голос
/ 25 марта 2019

Если вы хотите иметь поведение 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();
    };
  }, []);
1 голос
/ 25 марта 2019

Проблема вызвана закрытием.Поскольку эффект запускается только при начальном рендеринге, слушатель содержит ссылку 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; 
...