I cannot see the updated state inside of the helper method I'm using. All those worked in the class-based component, but it seems to be not the same when using hooks. Check out my comments.
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;
So the as you can see I'm trying to use updated state but all I'm getting there is 0 as a default state.
Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders.
To update the state, call the state updater function with the new state setState(newState) . Alternatively, if you need to update the state based on the previous state, supply a callback function setState(prevState => newState) .
If you want to have componentWillUnmount
behavior use useRef to access the updated values inside your listener:
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();
};
}, []);
If you use saveStateToLocalStorage
only inside useEffect
it is better to move it inside the callback of useEffect
. So it doesn't get recreated every render:
useEffect(() => {
function saveStateToLocalStorage(){
const videosPlayedDuration = {
[vimeoId]: videoProgressRef.current,
};
}
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);
return () => {
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);
saveStateToLocalStorage();
};
}, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With