为什么放在.then链中的函数会提前触发?(promise/async/await问题)
问题原因分析
- 你误以为async函数没有等待
.then内部逻辑执行,实际上async已经完整等待了所有链式回调执行完成,问题根源是React的状态更新机制和闭包特性,和异步等待逻辑无关。 - React的
setState(此处为setCards)属于异步批量更新操作,调用后不会立刻修改当前作用域下的cards变量,当前渲染闭包内的cards始终是本次渲染开始时的旧值(也就是你初始化的空数组),所以调用setCards后立刻打印cards.length必然返回0。 - 最后一个
.then回调中读取的cards依旧是当前闭包的旧值,无法获取到刚提交更新的状态,因此会出现“cards被赋值前就执行”的错觉。
修正方案
方案1:直接使用接口返回的data数据执行后续逻辑,不需要依赖状态更新
React.useEffect(() => { async function fetchCards() { try { const response = await fetch('https://api.pokemontcg.io/v2/cards?q=set.id:base1', { mode: 'cors', headers: { 'X-Api-key': '22173ccf-376e-4d12-8d50-8b25df6a8e13', }, }) const data = await response.json() const cardList = data.data console.log(cardList.length) // 此处可拿到正确的数组长度 setCards(cardList) updateDeck(getRandom(cardList, 4)) // 直接用接口返回的数组执行后续逻辑,不需要等状态更新 } catch (err) { console.error('卡片请求失败', err) } } fetchCards() }, []);
方案2:如果后续逻辑必须依赖更新后的cards状态,单独加useEffect监听
// 卡片请求逻辑 React.useEffect(() => { async function fetchCards() { try { const response = await fetch('https://api.pokemontcg.io/v2/cards?q=set.id:base1', { mode: 'cors', headers: { 'X-Api-key': '22173ccf-376e-4d12-8d50-8b25df6a8e13', }, }) const data = await response.json() setCards(data.data) } catch (err) { console.error('卡片请求失败', err) } } fetchCards() }, []); // 监听cards状态变化,状态更新后执行后续逻辑 React.useEffect(() => { if (cards.length) { console.log(cards.length) // 此处可拿到正确的数组长度 updateDeck(getRandom(cards, 4)) } }, [cards])
内容的提问来源于stack exchange,提问作者captaincustard
相关产品推荐
相关产品推荐

