【发布时间】:2021-11-16 20:14:20
【问题描述】:
我对 React 的了解并不多,但我边走边学。我在学校学习了基础知识,使用类组件(经典 React),但现在我正在研究 Hooks API(主要是因为我发现它更容易学习和管理,尽管似乎涉及更多关于异步行为的技巧) .所以我的问题可能看起来很愚蠢。
我发现 this thread 关于同一主题的 setState 行为,但这是关于类组件的。
在我当前的应用程序中,我尝试使用事件处理程序设置三种不同的状态。似乎最后一个状态是立即设置的,而其他两个状态在更改为实际值之前保持未定义一段时间。我正在使用 React-Native 组件进行移动开发,因此您会在 <SafeAreaView> 等代码中看到 sn-ps。
export default App = () => {
const [ destLong, setDestLong ] = useState();
const [ destLat, setDestLat ] = useState();
const [ startNav, setStartNav ] = useState(false);
const [ locations, setLocations ] = useState([
{
name: 'IKEA',
long: '-74.00653395444186',
lat: '40.68324646680103',
},
{
name: 'JFK Intl. Airport',
long: '-73.78131423688552',
lat: '40.66710279890186',
},
{
name: 'Microcenter',
long: '-74.00516039699959',
lat: '40.67195933297655',
}
]);
const startNavigation = (goinglong, goinglat) => {
setDestLong(goinglong);
setDestLat(goinglat);
setStartNav(true);
}
return (
<SafeAreaView style={styles.container}>
{ startNav ?
<MapView
destLong = {destLong}
destLat = {destLat}
/>
:
<View style={styles.buttonContainer}>
<ScrollView>
{
locations.map((location, i) => {
return(
<Card
style={styles.card}
key={i}
title={ location.name }
iconName="home"
iconType="Entypo"
description={ location.long + ", " + location.lat }
onPress={() => startNavigation(location.long, location.lat)}
/>
);
})
}
</ScrollView>
</View>
}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
buttonContainer: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center'
},
logo: {
width: '50%',
height: '50%',
resizeMode: 'contain'
},
card: {
marginBottom: 10,
}
});
这会引发错误,因为 MapView 期望 destLong 和 destLat 正确呈现。当我在 startNavigation 函数中进行控制台登录时,它似乎立即将 startNav 的状态更新为 true onPress,但 destLong 和 destLat 在设置之前保持未定义几个周期。
我尝试过这样的不同方法:
useEffect(() => {
setStartNav(true);
}, [destLong]);
const startNavigation = (goinglong, goinglat) => {
setDestLong(goinglong);
setDestLat(goinglat);
}
但它只会让应用程序崩溃(我猜是无限循环)。
我也尝试过完全删除 startNav 状态并像这样在 destLong 上呈现 <MapView>
{ destLong ?
<MapView
destLong = {destLong}
destLat = {destLat}
/>
:
<View style={styles.buttonContainer}>
...
</View>
}
但这也不起作用。
这让我想到了这个问题:Hooks API 是尊重 setState 的顺序,还是彼此异步执行?据我了解是后者。但是,您如何处理这种行为?
【问题讨论】:
-
简短回答,是的,订单保持不变。在对任何状态更新进行排队之前,您是否有一些异步代码?
-
我确实有一个异步地理定位功能在后台运行,主动获取当前位置并更新不同的状态。但是,为什么 startNav 状态会立即设置,而 destLong 和 destLat 状态在设置前几个周期仍未定义,即使它们被赋予了明确的值?
-
这很有趣,因为您共享的代码似乎是完全同步的。您在 Expo Snack 中有一个工作示例(或者您可以创建一个吗?)我们可以实时检查和调试?
-
通过 useState 设置状态实际上是异步的,或者更确切地说,状态更改被排入队列,然后在重新渲染后返回其新值。这意味着无法保证设置状态的顺序。它们将按顺序开火,但它们可能不会按相同的顺序设置。在你的情况下,我会像这样使用 useEffect: useEffect(() => { if(destLong && destLat && !startNav) { setStartNav(true); } }, [destLong, destLat, startNav]); const startNavigation = (goinglong, goinglat) => { setDestLong(goinglong); setDestLat(goinglat); }
-
什么、在哪里以及如何确定
destLong和destLat状态没有按预期更新?您看到的实际症状是什么?我已经看到并处理了与您类似的其他 SO 问题,它是返回纬度/经度坐标的地理位置数据,在数据进入之前需要几个“滴答”/渲染周期,您就可以开始计算距离/等。
标签: reactjs react-native react-hooks