Redux 状态未在 requestAnimationFrame 中更新
Redux state not updating in requestAnimationFrame
更新 Redux 状态时,更新后的状态会在组件中接收,但不会在 requestAnimationFrame
函数中接收。
即我们可以注销组件声明顶部附近的更新状态 (backgroundMode
) - 更新按预期记录:
const VideoCanvas = ({ videoRef }: IVideoCanvasProps) => {
...
console.log("backgroundMode", backgroundMode);
...
但是在requestAnimationFrame函数中,每帧只注销初始值(None
)
async function animate() {
...
// Does not receive updates from Redux store
console.log("animate backgroundMode", backgroundMode);
...
animationFrame.current = requestAnimationFrame(animate);
控制台输出如下所示:
backgroundMode None
(20) VideoCanvas.tsx:71 animate backgroundMode None
// change dropdown to blur mode
VideoCanvas.tsx:26 backgroundMode Blur
(23) VideoCanvas.tsx:71 animate backgroundMode None
// change dropdown to mask mode
VideoCanvas.tsx:26 backgroundMode Mask
(62) VideoCanvas.tsx:71 animate backgroundMode None
将 backgroundMode
添加到启动动画的 useEffect 的依赖项中,只会导致生成两个动画线程,从而使问题恶化。就目前而言,此效果如下所示:
useEffect(() => {
animationFrame.current = requestAnimationFrame(animate);
return () => {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
}
};
}, [bodyPixNet]);
有问题的文件可以在我的 GitHub here
上完整查看
如有任何建议,我们将不胜感激!
这听起来像是 animate
函数中发生的旧的“陈旧状态封闭”问题。由于您正在递归调用 requestAnimationFrame
并从动画开始的渲染周期传递 animate
的值,因此您可能希望也在 ref 中缓存 backgroundMode
的副本,以便它可以随时更新,也可以随时读取当前值。使用 useEffect
挂钩更新缓存。
const backgroundModeRef = React.useRef(backgroundMode);
React.useEffect(() => {
backgroundModeRef.current = backgroundMode;
}, [backgroundMode]);
在animate
函数中,引用缓存的ref值。
async function animate() {
...
// Does not receive updates from Redux store
console.log("animate backgroundMode", backgroundModeRef.current);
...
animationFrame.current = requestAnimationFrame(animate);
更新 Redux 状态时,更新后的状态会在组件中接收,但不会在 requestAnimationFrame
函数中接收。
即我们可以注销组件声明顶部附近的更新状态 (backgroundMode
) - 更新按预期记录:
const VideoCanvas = ({ videoRef }: IVideoCanvasProps) => {
...
console.log("backgroundMode", backgroundMode);
...
但是在requestAnimationFrame函数中,每帧只注销初始值(None
)
async function animate() {
...
// Does not receive updates from Redux store
console.log("animate backgroundMode", backgroundMode);
...
animationFrame.current = requestAnimationFrame(animate);
控制台输出如下所示:
backgroundMode None
(20) VideoCanvas.tsx:71 animate backgroundMode None
// change dropdown to blur mode
VideoCanvas.tsx:26 backgroundMode Blur
(23) VideoCanvas.tsx:71 animate backgroundMode None
// change dropdown to mask mode
VideoCanvas.tsx:26 backgroundMode Mask
(62) VideoCanvas.tsx:71 animate backgroundMode None
将 backgroundMode
添加到启动动画的 useEffect 的依赖项中,只会导致生成两个动画线程,从而使问题恶化。就目前而言,此效果如下所示:
useEffect(() => {
animationFrame.current = requestAnimationFrame(animate);
return () => {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
}
};
}, [bodyPixNet]);
有问题的文件可以在我的 GitHub here
上完整查看如有任何建议,我们将不胜感激!
这听起来像是 animate
函数中发生的旧的“陈旧状态封闭”问题。由于您正在递归调用 requestAnimationFrame
并从动画开始的渲染周期传递 animate
的值,因此您可能希望也在 ref 中缓存 backgroundMode
的副本,以便它可以随时更新,也可以随时读取当前值。使用 useEffect
挂钩更新缓存。
const backgroundModeRef = React.useRef(backgroundMode);
React.useEffect(() => {
backgroundModeRef.current = backgroundMode;
}, [backgroundMode]);
在animate
函数中,引用缓存的ref值。
async function animate() {
...
// Does not receive updates from Redux store
console.log("animate backgroundMode", backgroundModeRef.current);
...
animationFrame.current = requestAnimationFrame(animate);