我正在尝试构建我的第一个基于 React Hooks 的 React 应用程序,但我很难弄清楚我的状态/ Prop 和重新渲染发生了什么。我正在创建一些小型猜谜游戏。
我有一个父组件 GameContent,它传递给它的子组件(Round)一些 Prop :
- currentRound(数字)
- roundData(对象)
- shiftRounds(函数)
通过“shiftRounds”我告诉我的父组件:“这个玩家给出了正确的答案”,然后函数改变回合和分数(都在父状态)。
虽然看起来很简单,但我在子组件中检查答案是否正确的函数总是从第一轮获取数据。
我尝试了 React.useRef,尝试了不同的状态配置,但仍然找不到解决方案。
<GameContent />
const GameContent = ({ gameOptions, gameFinish }) => {
const [gameData, setGameData] = useState([]);
const [round, setRound] = useState(1);
const [score, setScore] = useState([0, 0]);
const [ligue, dateFrom, dateTo, rounds, player1, player2] = gameOptions;
useEffect(() => {
//
// Function fetches football matches.
//
(async () => {
const matchesData = await fetchMatches(ligue, dateFrom, dateTo)
setGameData(matchesData);
})();
}, [])
const nextRound = (scoringPlayer) => {
if (round <= rounds) {
setScore(score => {
score[scoringPlayer] += 1;
return score
});
setRound(round => round + 1);
} else {
finishGame()
}
}
return (
<div className="text-center">
<h2>Round {round}</h2>
<h3>Score</h3>
<h2>{`${score[0]} : ${score[1]}`}</h2>
{(gameData.length) ? <Round currentRound={round} roundData={gameData[round - 1]} shiftRounds={nextRound} players={[player1, player2]} /> : <h1>Loading...</h1>}
</div>
)
}
<Round />
const Round = (props) => {
const [isCheckingAnswer, setIsCheckingAnswer] = useState(false);
useEffect(() => {
//
// Set eventListeners for keydown (too capture player's answer)
//
document.addEventListener('keydown', (e) => { handleKeyPress(e) });
setIsCheckingAnswer(false);
return () => {
document.removeEventListener('keydown', (e) => { handleKeyPress(e) });
}
}, [props.roundData])
const handleKeyPress = (e) => {
if (!isCheckingAnswer) {
e.preventDefault();
setIsCheckingAnswer(true);
if (keysMap[e.key] === checkGoodAnswer(props.roundData.homeTeamScore, props.roundData.awayTeamScore)) {
const winingPlayer = isNaN(e.key / 2) ? 0 : 1;
props.shiftRounds(winingPlayer);
} else {
setIsCheckingAnswer(false);
}
} else {
return
}
}
return (
<>
<Row>
<Col xs={4}>
<h2>{props.roundData.homeTeam}</h2>
</Col>
<Col xs={4}>
<h2>vs</h2>
</Col>
<Col xs={4}>
<h2>{props.roundData.awayTeam}</h2>
</Col>
</Row>
<Row className="justify-content-center my-5">
<Col xs={4}>
<h3>{props.players[0]}</h3>
</Col>
<Col xs={4}>
<h3>{props.players[1]}</h3>
</Col>
</Row>
</>
)
}
辅助函数
const checkGoodAnswer = (homeTeamScore, awayTeamScore) => {
if (homeTeamScore > awayTeamScore) {
return 'homeTeam'
} else if (homeTeamScore < awayTeamScore) {
return 'awayTeam'
} else {
return 'draw'
}
}
const keysMap = {
'a': 'homeTeam',
'w': 'draw',
'd': 'awayTeam',
'4': 'homeTeam',
'8': 'draw',
'6': 'awayTeam',
}
获取的数据样本:
[
{awayTeam: "Paris Saint-Germain FC"
awayTeamScore: 2
homeTeam: "Manchester United FC"
homeTeamScore: 0},
{
awayTeam: "FC Porto"
awayTeamScore: 1
homeTeam: "AS Roma"
homeTeamScore: 2
},
...
]
最佳答案
您应该添加 ALL 在您的 useEffect
中使用的相关变量/函数作为依赖项。
来自docs :
... make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect
例如,在您的第一个效果中,您的数组中没有依赖项:
useEffect(() => {
//
// Function fetches football matches.
//
(async () => {
const matchesData = await fetchMatches(ligue, dateFrom, dateTo)
setGameData(matchesData);
})();
}, [])
但是你确实使用了ligue
, dateFrom
, dateTo
等...
React 团队提供了一个很好的 eslint 插件(eslint-plugin-react-hooks),可以帮助您解决此类问题,我建议您尝试一下。
关于javascript - React hooks props 和 state 通信问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55314233/