React Native石头剪刀布游戏result变量未实时更新问题求助
石头剪刀布游戏结果实时显示问题解决
问题描述
开发React Native石头剪刀布游戏时,功能整体正常,但result变量无法实时显示当前对局结果,总是显示上一局的结果。例如:
- 当我选择石头且电脑也选择石头时,本该显示平局,但界面无显示;
- 当我再次选择石头而电脑选择纸时,
result却显示上一局的平局结果。
原代码
const RockPaperScissors = () => { const [userOption, setUserOption] = useState("user") const [computerOption, setComputerOption] = useState("computer") const [result, setResult] = useState("") const options = ["paper", "rock", "scissors"] const rockOption = () => { let choice = Math.floor(Math.random()*3) setComputerOption(options[choice]) } const resultRock = () => { setUserOption("rock") if (computerOption == userOption){ setResult("tie") } else { setResult("no tie") } } const combineRock = () => { rockOption() resultRock() } const RenderComputer = () => { if (computerOption == "paper") { return ( <FontAwesome name="hand-paper-o" size={70} color="black" /> ) } if (computerOption == "rock") { return ( <FontAwesome name="hand-rock-o" size={70} color="black" /> ) } if (computerOption == "scissors") { return ( <FontAwesome name="hand-scissors-o" size={70} color="black" /> ) } } return ( <View style={styles.container} > <Text style={styles.title} > Rock - Paper - Scissors </Text> <View style={styles.containerGame} > <View style={styles.computer} > <Text>Computer Option</Text> <RenderComputer/> </View> <Text>Result: {result}</Text> <View style={styles.user} > <Text>Your Option</Text> <FontAwesome name="hand-rock-o" size={70} color="black" onPress={combineRock}/> {/* <FontAwesome name="hand-paper-o" size={70} color="black" onPress={rockOption}/> <FontAwesome name="hand-scissors-o" size={70} color="black" onPress={rockOption}/> */} </View> </View> </View> ) }
问题原因
React的useState更新是异步的。在combineRock中,先调用rockOption设置computerOption,紧接着调用resultRock时,computerOption的新值还未生效,resultRock使用的是更新前的旧状态,导致结果计算错误,显示上一局的结果。
解决方案
方案1:使用useEffect监听状态变化计算结果
通过useEffect监听userOption和computerOption的变化,每当这两个状态更新时,自动计算并更新result:
import { useState, useEffect } from 'react'; const RockPaperScissors = () => { const [userOption, setUserOption] = useState("") const [computerOption, setComputerOption] = useState("") const [result, setResult] = useState("") const options = ["paper", "rock", "scissors"] // 监听状态变化,自动计算结果 useEffect(() => { if (userOption && computerOption) { setResult(userOption === computerOption ? "tie" : "no tie") } }, [userOption, computerOption]) const rockOption = () => { let choice = Math.floor(Math.random()*3) setComputerOption(options[choice]) } const combineRock = () => { setUserOption("rock") rockOption() } const RenderComputer = () => { if (computerOption == "paper") { return <FontAwesome name="hand-paper-o" size={70} color="black" /> } if (computerOption == "rock") { return <FontAwesome name="hand-rock-o" size={70} color="black" /> } if (computerOption == "scissors") { return <FontAwesome name="hand-scissors-o" size={70} color="black" /> } return null } return ( <View style={styles.container} > <Text style={styles.title} >Rock - Paper - Scissors</Text> <View style={styles.containerGame} > <View style={styles.computer} > <Text>Computer Option</Text> <RenderComputer/> </View> <Text>Result: {result}</Text> <View style={styles.user} > <Text>Your Option</Text> <FontAwesome name="hand-rock-o" size={70} color="black" onPress={combineRock}/> {/* <FontAwesome name="hand-paper-o" size={70} color="black" onPress={() => {setUserOption("paper"); rockOption()}}/> <FontAwesome name="hand-scissors-o" size={70} color="black" onPress={() => {setUserOption("scissors"); rockOption()}}/> */} </View> </View> </View> ) }
方案2:合并逻辑,直接使用最新值计算结果
将用户选择、电脑选择、结果计算合并到一个函数中,直接用生成的电脑选择值计算结果,避免依赖异步更新的state:
const RockPaperScissors = () => { const [userOption, setUserOption] = useState("") const [computerOption, setComputerOption] = useState("") const [result, setResult] = useState("") const options = ["paper", "rock", "scissors"] const handleUserChoice = (choice) => { setUserOption(choice) // 生成电脑选择 const computerChoice = options[Math.floor(Math.random()*3)] setComputerOption(computerChoice) // 直接计算结果 setResult(choice === computerChoice ? "tie" : "no tie") } const RenderComputer = () => { if (computerOption == "paper") { return <FontAwesome name="hand-paper-o" size={70} color="black" /> } if (computerOption == "rock") { return <FontAwesome name="hand-rock-o" size={70} color="black" /> } if (computerOption == "scissors") { return <FontAwesome name="hand-scissors-o" size={70} color="black" /> } return null } return ( <View style={styles.container} > <Text style={styles.title} >Rock - Paper - Scissors</Text> <View style={styles.containerGame} > <View style={styles.computer} > <Text>Computer Option</Text> <RenderComputer/> </View> <Text>Result: {result}</Text> <View style={styles.user} > <Text>Your Option</Text> <FontAwesome name="hand-rock-o" size={70} color="black" onPress={() => handleUserChoice("rock")}/> {/* <FontAwesome name="hand-paper-o" size={70} color="black" onPress={() => handleUserChoice("paper")}/> <FontAwesome name="hand-scissors-o" size={70} color="black" onPress={() => handleUserChoice("scissors")}/> */} </View> </View> </View> ) }
说明
两种方案都能解决延迟显示的问题:
- 方案1适合状态更新逻辑分散的场景,利用
useEffect自动同步结果; - 方案2逻辑更集中,代码更简洁,适合将操作合并管理的场景。
内容的提问来源于stack exchange,提问作者Tommy Solano Peñafiel
相关产品推荐
相关产品推荐

