反应功能不使用更新状态
react function not using updated state
我的 handleKeyUp 函数没有使用状态中的任何新值。在函数中,playingTrackInd 始终等于 -1,即使 playingTrackInd 的状态已更新为其他内容。
import React, { useEffect, useRef, useState } from 'react';
import { Container } from 'react-bootstrap';
export interface Track {
artist: string,
title: string,
uri: string,
albumUrl: string,
previewUrl?: string,
}
export default function Dashboard() {
const [playingTrackInd, setPlayingTrackInd] = useState<number>(-1);
const tracks = useRef<Array<Track>>([]);
// add keylistener
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
}, []);
// this function always has playingTrackInd as -1, even when the state has been updated by setPlayingTrackInd
function handleKeyUp(e: any) {
if (e.keyCode === 39) {
// right arrow pressed
if (playingTrackInd === tracks.current.length - 1) {
getRandomTrack(() => setPlayingTrackInd(prevInd => prevInd + 1));
}
else {
setPlayingTrackInd(prevInd => prevInd + 1)
}
}
else if (e.keyCode === 37) { // left arrrow key pressed
if (playingTrackInd > 0) {
setPlayingTrackInd(prevInd => prevInd - 1);
}
}
}
// function that gets random track and adds it to tracks
function getRandomTrack(callback?: Function) {
getRandomTrackFromApi().then((track) => {
tracks.current.push(track);
if (callback) {
callback();
}
})
}
// get first random track and set playingTrackInd to 0. This happens as soon as the component is loaded
useEffect(() => {
if (playingTrackInd === -1) {
getRandomTrack(() => setPlayingTrackInd(0));
}
getRandomTrack();
getRandomTrack();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
(component that depends on tracks[playingTrackInd])
);
}
我不明白为什么只有在handleKeyUp函数中playingTrackInd总是-1。在其他任何地方,包括 return 语句,它都是正确的值。谢谢
问题出在下面的效果上:
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
}, []);
如你所见,你注册了一次handleKeyUp
(效果被触发一次,挂载时,因为deps数组是空的)。 handleKeyUp
通过闭包 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) 记住了 playingTrackInd
的最后一个值。 playingTrackInd
更新时,组件重新呈现,创建新的 handleKeyUp
函数,但您已经注册了记住旧值的 handleKeyUp
,并且您没有更新该侦听器。
您可以解决该问题,例如将 handleKeyUp
传递给依赖项数组,如下所示:
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
return () => {
document.removeEventListener('keyup', handleKeyUp);
}
}, [handleKeyUp]);
在注册新的侦听器之前不要忘记删除侦听器。解决方案并不理想,因为每次渲染都会创建 handleKeyUp
函数。您的第二个 useEffect
挂钩中存在同样的问题。
我强烈建议将您的函数包装到 useCallback
(https://reactjs.org/docs/hooks-reference.html#usecallback) 中,并在 deps 数组中传递所有依赖项。这样你的功能就不会在每次渲染时都创建,而只会在它们的依赖关系发生变化时才创建。
另一件事是有一个 eslint 规则可以帮助您跟踪 deps 数组中所有必需的 deps,检查 exhaustive-deps
https://reactjs.org/docs/hooks-rules.html
我的 handleKeyUp 函数没有使用状态中的任何新值。在函数中,playingTrackInd 始终等于 -1,即使 playingTrackInd 的状态已更新为其他内容。
import React, { useEffect, useRef, useState } from 'react';
import { Container } from 'react-bootstrap';
export interface Track {
artist: string,
title: string,
uri: string,
albumUrl: string,
previewUrl?: string,
}
export default function Dashboard() {
const [playingTrackInd, setPlayingTrackInd] = useState<number>(-1);
const tracks = useRef<Array<Track>>([]);
// add keylistener
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
}, []);
// this function always has playingTrackInd as -1, even when the state has been updated by setPlayingTrackInd
function handleKeyUp(e: any) {
if (e.keyCode === 39) {
// right arrow pressed
if (playingTrackInd === tracks.current.length - 1) {
getRandomTrack(() => setPlayingTrackInd(prevInd => prevInd + 1));
}
else {
setPlayingTrackInd(prevInd => prevInd + 1)
}
}
else if (e.keyCode === 37) { // left arrrow key pressed
if (playingTrackInd > 0) {
setPlayingTrackInd(prevInd => prevInd - 1);
}
}
}
// function that gets random track and adds it to tracks
function getRandomTrack(callback?: Function) {
getRandomTrackFromApi().then((track) => {
tracks.current.push(track);
if (callback) {
callback();
}
})
}
// get first random track and set playingTrackInd to 0. This happens as soon as the component is loaded
useEffect(() => {
if (playingTrackInd === -1) {
getRandomTrack(() => setPlayingTrackInd(0));
}
getRandomTrack();
getRandomTrack();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
(component that depends on tracks[playingTrackInd])
);
}
我不明白为什么只有在handleKeyUp函数中playingTrackInd总是-1。在其他任何地方,包括 return 语句,它都是正确的值。谢谢
问题出在下面的效果上:
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
}, []);
如你所见,你注册了一次handleKeyUp
(效果被触发一次,挂载时,因为deps数组是空的)。 handleKeyUp
通过闭包 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) 记住了 playingTrackInd
的最后一个值。 playingTrackInd
更新时,组件重新呈现,创建新的 handleKeyUp
函数,但您已经注册了记住旧值的 handleKeyUp
,并且您没有更新该侦听器。
您可以解决该问题,例如将 handleKeyUp
传递给依赖项数组,如下所示:
useEffect(() => {
document.addEventListener('keyup', handleKeyUp);
return () => {
document.removeEventListener('keyup', handleKeyUp);
}
}, [handleKeyUp]);
在注册新的侦听器之前不要忘记删除侦听器。解决方案并不理想,因为每次渲染都会创建 handleKeyUp
函数。您的第二个 useEffect
挂钩中存在同样的问题。
我强烈建议将您的函数包装到 useCallback
(https://reactjs.org/docs/hooks-reference.html#usecallback) 中,并在 deps 数组中传递所有依赖项。这样你的功能就不会在每次渲染时都创建,而只会在它们的依赖关系发生变化时才创建。
另一件事是有一个 eslint 规则可以帮助您跟踪 deps 数组中所有必需的 deps,检查 exhaustive-deps
https://reactjs.org/docs/hooks-rules.html