我正在为“ React Native”开发一款猜谜游戏,在该游戏中,用户输入了一个数字,然后电话尝试猜测它。每次电话产生一个猜测时,用户都可以单击“大/小”。当用户输入数字并且计算机进行猜测时,我们将被带到屏幕上进行游戏。
屏幕上的游戏未呈现。在屏幕上渲染游戏的逻辑位于useEffect()
内问题
useEffect在安装阶段仅触发一次,再也不会触发?
const { userSelectedNumber, onGameOver } = props;
useEffect(() => {
console.log(currentGuess, userSelectedNumber);
if (currentGuess === userSelectedNumber) {
onGameOver(rounds);
}
}, [userSelectedNumber, onGameOver]);*emphasized text*
(../ screens / GameScreen.js)
我们应该在currentGuess === userSelectedNumber
时退出GameScreen,但是此代码只能运行一次。
下面的GameScreen的完整代码:
import React, { useState, useRef, useEffect } from "react";
import { View, StyleSheet, Button, Text, Alert } from "react-native";
import NumberContainer from "../components/NumberContainer";
import Card from "../components/Card";
const randNumberGeneratorBetween = (min, max, exclude) => {
min = Math.ceil(min);
max = Math.floor(max);
const randNum = Math.floor(Math.random() * (max - min)) + min;
if (randNum === exclude) {
return randNumberGeneratorBetween(1, 100, exclude);
} else {
return randNum;
}
};
const GameScreen = props => {
const [currentGuess, setCurrentGuess] = useState(
randNumberGeneratorBetween(1, 100, props.userSelectedNumber)
);
const [rounds, setRounds] = useState(0);
const currentLow = useRef(1);
const currentHigh = useRef(100);
const { userSelectedNumber, onGameOver } = props;
useEffect(() => {
console.log(currentGuess, userSelectedNumber);
if (currentGuess === userSelectedNumber) {
onGameOver(rounds);
}
}, [userSelectedNumber, onGameOver]);
const nextGuessHandler = direction => {
if (
(direction === "lower" && currentGuess < props.userSelectedNumber) ||
(direction === "greater" && currentGuess > props.userSelectedNumber)
) {
Alert.alert("Don't Lie", "You know this is wrong", [
{ text: "Sorry", style: "cancel" }
]);
}
if (direction === "lower") {
currentHigh.current = currentGuess;
} else {
currentLow.current = currentGuess;
}
const nextNumber = randNumberGeneratorBetween(
currentLow.current,
currentHigh.current,
currentGuess
);
console.log('nextNumber',nextNumber);
setCurrentGuess(nextNumber);
setRounds(currRounds => currRounds + 1);
console.log('currRound',rounds);
};
return (
<View style={styles.screen}>
<Text>Opponents Guess</Text>
<NumberContainer>{currentGuess}</NumberContainer>
<Card style={styles.buttonContainer}>
<Button
title="Lower"
onPress={nextGuessHandler.bind(this, "lower")}
></Button>
<Button
title="Greater"
onPress={nextGuessHandler.bind(this, "greater")}
></Button>
</Card>
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
padding: 10,
alignItems: "center"
},
buttonContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginTop: 20,
width: 300,
maxWidth: "80%"
}
});
export default GameScreen;
项目可以在这里找到: https://codesandbox.io/s/github/SMasood1/guessingGame?file=/screens/GameScreen.js:852-1039
答案 0 :(得分:2)
您需要在useEffect挂钩中的依赖项数组中添加rounds
和currentGuess
useEffect(() => {
console.log(currentGuess, userSelectedNumber);
if (currentGuess === userSelectedNumber) {
onGameOver(rounds);
}
}, [userSelectedNumber, onGameOver,currentGuess,rounds]);
使用道具初始化状态也被认为是一种反模式,所以我建议添加另一个useEffect钩子:
useEffect(()=>{
setCurrentGuess(randNumberGeneratorBetween(1, 100, props.userSelectedNumber))
},[props.userSelectedNumber]);
答案 1 :(得分:1)
只要依赖项数组的任何值发生更改,useEffect挂钩都会使组件更新。确保用于触发该钩子的值实际上正在更改。
答案 2 :(得分:0)
您可以通过在 navigation.navigate
调用中提供时间戳来优雅地触发 useEffect
例如
// someComponent.tsx
navigation.navigate('Home', {
showSubscriptionModal: true
})
// HomeScreen.tsx
const showSubscriptionModal = props.route.params?.showSubscriptionModal ?? false
useEffect(() => {
if(showSubscriptionModal) setIsShowingModal(true)
},[showSubscriptionModal])
只会触发一次,而
// someComponent.tsx
navigation.navigate('Home', {
showSubscriptionModal: true,
updateTs: new Date()
})
// HomeScreen.tsx
const showSubscriptionModal = props.route.params?.showSubscriptionModal ?? false
useEffect(() => {
if(props.route.params?.showSubscriptionModal) setIsShowingModal(true)
},[showSubscriptionModal, props.route.params?.updateTs])
每次您通过 navigation.navigate()