无法使用挂钩在方法辅助函数中看到状态
Can't see state inside method helper function using hooks
我在我正在使用的辅助方法中看不到更新后的状态。所有这些都在基于 class 的组件中工作,但在使用 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 作为默认状态。
问题是由于关闭引起的。由于效果 运行 仅在初始渲染时,侦听器持有 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;
如果您想要 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();
};
}, []);
如果您只在 useEffect
中使用 saveStateToLocalStorage
,最好将其移动到 useEffect
的回调中。所以它不会在每次渲染时都重新创建:
useEffect(() => {
function saveStateToLocalStorage(){
const videosPlayedDuration = {
[vimeoId]: videoProgressRef.current,
};
}
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);
return () => {
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);
saveStateToLocalStorage();
};
}, []);
我在我正在使用的辅助方法中看不到更新后的状态。所有这些都在基于 class 的组件中工作,但在使用 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 作为默认状态。
问题是由于关闭引起的。由于效果 运行 仅在初始渲染时,侦听器持有 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;
如果您想要 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();
};
}, []);
如果您只在 useEffect
中使用 saveStateToLocalStorage
,最好将其移动到 useEffect
的回调中。所以它不会在每次渲染时都重新创建:
useEffect(() => {
function saveStateToLocalStorage(){
const videosPlayedDuration = {
[vimeoId]: videoProgressRef.current,
};
}
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);
return () => {
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);
saveStateToLocalStorage();
};
}, []);