setState挂钩未更新-尽管prevState显示了正确的值



我使用状态变量来跟踪我以前的状态。

动画工作(没有索引(,但当我做

const [index, setIndex] = useState(0)
useEffect(() => {
animation.addListener((scroll) => {
setTimeout(function() {
let position = Math.floor(scroll.value / cardWidth + 0.75);
if (position >= restaurants.length - 1) position = restaurants.length - 1;
if (position <= 0) position = 0;
console.log("position: ", position, "index: ", index)
if (index !== position) {
setIndex(prevState => {
console.log("previous: ", prevState, "position: ", position, "index: ", index)
return position
});
const { coordinate } = restaurants[position];
mapRef.current.animateCamera({
center: {
latitude: coordinate.latitude,
longitude: coordinate.longitude,
},
altitude: 2000, // zooms in when viewing specific location
}, {duration: 1000}) // not sure if duration is actually doing anything
}
}, 3000);
});
return function cleanUp(): void { animation.removeAllListeners(); }
}, []);

索引从不更新。我试着在setState函数中检查prevState,它会更新,但如果我在setIndex之外打印索引,它不会更新。我该怎么解决这个问题?编辑:发现问题。函数永远不会停止,因为它一直在侦听。如何重构代码以结束函数,从而改变状态

控制台输出

position:  1 index:  0
previous:  1 position:  1 index:  0
position:  1 index:  0
previous:  1 position:  1 index:  0
position:  1 index:  0
previous:  1 position:  1 index:  0
position:  1 index:  0
previous:  2 position:  2 index:  0
position:  2 index:  0
previous:  2 position:  2 index:  0
position:  2 index:  0
previous:  3 position:  3 index:  0
position:  3 index:  0
previous:  3 position:  3 index:  0
position:  3 index:  0

编辑:我找到的答案

正如下面许多人所说的,useState是异步的,将等待函数结束后再更新。侦听器是一个在激活后一直运行的函数,直到下一次渲染。因此,值只有在重新渲染时才会更新。我决定切换到useRef,因为它是同步的,并允许我在不重新渲染的情况下保持最新的值。

正确,原因如下:

  • addListener中创建一个闭包,捕获index的初始值,该值通过useState(0)设置为0
  • 您为useEffect提供了一个空的依赖项列表,这意味着它在组件装载时只运行一次

要修复它,您应该向useEffect的依赖项列表提供index,以允许它重新运行,从而获取最新的index

useEffect(() => { ... }, [index]);

或者,如果您发现取消挂起/重新挂起事件处理程序有问题,可以向setIndex传递一个函数,该函数允许您访问以前的值,例如

setIndex(oldIndex => {
let newIndex = oldIndex;
if (oldIndex != position) {
// update newIndex 
}
return newIndex;
});

最新更新