React中useEffect调用useCallback函数致状态重复更新问题
解决React Blackjack Hook状态重复更新问题
问题根源
- 状态更新嵌套调用:在
setDeck的回调函数内部调用setDealerHand,这种耦合式的状态更新,加上React开发环境严格模式会重复执行状态更新函数,直接导致多次触发更新。 - 重复触发源叠加:处理庄家得分不足17的自动发牌
useEffect,可能和监听isDealerHidden的useEffect重复调用了drawDealerCard,加剧了重复更新问题。
修复方案
方案1:拆分状态更新,避免嵌套耦合
不要在一个状态更新的回调里嵌套另一个状态更新,将两个状态的更新逻辑分开:
const drawDealerCard = useCallback(() => { console.log("drawDealerCard"); // 先取当前牌组最后一张牌 const newCard = deck[deck.length - 1]; if (!newCard) return; // 分别更新牌组和庄家手牌 setDeck(prev => prev.slice(0, -1)); setDealerHand(prev => [...prev, newCard]); }, [deck]);
注意:这种方式依赖deck状态,要确保闭包能获取到最新的deck值。
方案2:用useReducer统一管理关联状态
由于牌组(deck)和庄家手牌(dealerHand)是强关联的状态,一次操作需要同时更新两者,用useReducer能更清晰地管理状态逻辑,避免耦合:
// 定义状态更新的reducer函数 const gameReducer = (state, action) => { switch (action.type) { case 'DRAW_DEALER_CARD': { const newDeck = [...state.deck]; const newCard = newDeck.pop(); if (!newCard) return state; return { ...state, deck: newDeck, dealerHand: [...state.dealerHand, newCard] }; } // 可扩展其他游戏操作类型,比如玩家发牌、重置游戏等 default: return state; } }; // 在组件中初始化useReducer const [state, dispatch] = useReducer(gameReducer, { deck: initialDeck, // 你的初始牌组数据 dealerHand: initialDealerHand // 庄家初始手牌 }); const { deck, dealerHand } = state; // 重写发牌函数 const drawDealerCard = useCallback(() => { console.log("drawDealerCard"); dispatch({ type: 'DRAW_DEALER_CARD' }); }, []); // 监听isDealerHidden的useEffect useEffect(() => { if (!isDealerHidden) { console.log("useEffect isDealerHidden changed"); drawDealerCard(); } }, [isDealerHidden, drawDealerCard]); // 庄家自动发牌的useEffect useEffect(() => { // 实现庄家手牌得分计算逻辑 const calculateDealerScore = (hand) => { // 你的得分计算代码 }; const dealerScore = calculateDealerScore(dealerHand); // 仅在庄家未隐藏手牌且得分不足17时发牌 if (!isDealerHidden && dealerScore < 17 && deck.length > 0) { drawDealerCard(); } }, [isDealerHidden, dealerHand, deck.length, drawDealerCard]);
额外检查点
- 确认React严格模式:开发环境下严格模式会重复执行状态更新、
useEffect等逻辑,用于检测副作用,生产环境不会出现,但代码要避免依赖单次执行的逻辑。 - 检查自动发牌的
useEffect依赖项:确保不会因状态变化无限触发,比如添加牌组长度判断,避免无牌可发时重复调用。
内容的提问来源于stack exchange,提问作者indiehjaerta
相关产品推荐
相关产品推荐

