#reactjs
#reactjs
Вопрос:
Сейчас я играю с хуками. Мой код выглядит следующим образом:
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) amp;amp;
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
in метод saveStateToLocalStorage
не будет обновляться, и onPause
метод не приведет к надлежащему сохранению в localStorage (это сохранит 0). Есть ли способ сделать это с помощью хуков, не используя class component с componentWillUnmount
жизненным циклом?
Ответ №1:
Вы должны понимать, как useEffect
работает.
useEffect(() => {
// your code
return () => {
// your clearup code
};
}, [videoProgress]); // => This is the key point. It's called dependency
Всякий раз, когда зависимость изменяется, react повторно запускает useEffect
. Ваше videoProgress
значение изменяется через интервал времени (может быть, через 1 секунду, я не знаю). Вот почему react повторно запускает useEffect.
Вы можете сделать это.
useEffect(() => {
// your code
return () => {
// your clearup code. =>> This block will work as componentWillUnmount
};
}, []); // => No Dependency
Или вы можете добавить зависимость от вашего идентификатора видео (в соответствии с вашими требованиями).
Один удобный пример
useEffect(() => {
// This block (before the return) will act as componentDidMount
return () => {
// This block will work as componentWillUnmount
};
}, []); // => beacase of No Dependency
Примечание с одной стороны: у вас может быть эффект многократного использования.
Комментарии:
1. В дополнение к этому у вас может быть несколько
useEffect
функций, так что у вас может быть одна, которая запускается один раз, передавая пустой массив, а другая, которая выполняет то, что должно быть сделано, когдаvideoProgress
изменилось.2. Обновленный Anwser с несколькими дополнительными деталями
3. Хорошо, я понял, но когда я использую пустой массив [ ], мой компонент не обновляется, и в методе saveStateToLocalStorage сохраняется начальное значение 0.