【发布时间】:2021-01-11 02:55:29
【问题描述】:
我无法理解。简而言之,我有这两个变量在状态中使用
questionLoaded
gameOver
这个组件需要等待,直到它使用函数selectRandomQuestion完成获取数据。
因此,如果我删除questionLoaded,它会在循环地图时给我异常。
现在我必须创建另一个变量来检查游戏何时结束以取消渲染此组件,因此三元条件questionLoaded || gameOver ?
我尝试检查变量currentQuestion 以有条件地渲染,但由于某种原因,它会在循环遍历此属性的options 数组中的地图时出现异常。这意味着currentQuestion 在它自己的子属性options 在达到条件检查时有任何数据之前首先获取数据
问题是这看起来有点脏,我只用了几个星期的 react,我不确定这是否是处理状态更新的适当方法,或者是否有更好的方法来处理它.
总结一下,我的问题是在渲染组件的时候,当渲染依赖于一些条件时,我经常需要等待状态更新,而每次我需要一个新的条件,这意味着我需要另一组逻辑使用另一个状态变量。这意味着使用额外的逻辑创建另一个 useEffect,并在该变量更新时触发。
import React, { useState, useEffect } from 'react';
import './GuessPicture.css';
import questions from './data/questions.js';
function GuessPicture() {
const [currentQuestion, setCurrentQuestion] = useState({});
const [unansweredQuestions, setUnansweredQuestions] = useState([]);
const [answeredQuestions, setAnsweredQuestions] = useState([]);
const [questionLoaded, setQuestionLoaded] = useState(false);
const [gameOver, setGameOver] = useState(false);
useEffect(() => {
setUnansweredQuestions(questions);
selectRandomQuestion();
setQuestionLoaded(true);
}, []);
useEffect(() => {
if (unansweredQuestions.length > 0) nextQuestion();
else alert('game over');
}, [unansweredQuestions]);
function selectRandomQuestion() {
const index = Math.floor(Math.random() * questions.length);
let selectedQuestion = questions[index];
selectedQuestion.options = shuffle(selectedQuestion.options);
setCurrentQuestion(selectedQuestion);
}
function nextQuestion() {
const index = Math.floor(Math.random() * unansweredQuestions.length);
let selectedQuestion = unansweredQuestions[index];
selectedQuestion.options = shuffle(selectedQuestion.options);
setCurrentQuestion(selectedQuestion);
}
// Fisher Yates Shuffle Algorithm
function shuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
const onClickOption = (event) => {
if (currentQuestion.correctValue == event.target.dataset.value) {
setAnsweredQuestions((answeredQuestions) => [
...answeredQuestions,
currentQuestion,
]);
const newUnansweredQuestions = unansweredQuestions.filter(
(item) => item.id != currentQuestion.id
);
setUnansweredQuestions(newUnansweredQuestions);
} else alert('Wrong');
};
return (
<>
{questionLoaded || gameOver ? (
<div className="guess-picture-container">
<div className="guess-picture">
<img src={currentQuestion.image} alt="English 4 Fun" />
</div>
<div className="guess-picture-answers-grid">
{currentQuestion.options.map((key) => (
<button
key={key.value}
onClick={onClickOption}
data-value={key.value}
>
{key.display}
</button>
))}
</div>
</div>
) : null}
</>
);
}
export default GuessPicture;
【问题讨论】:
-
Hooks 大多只是简单的 js 代码。无论复杂的逻辑如何发展,总有办法清理代码。干,在适当的水平抽象。你知道这些规则。钩子的一个好处是它们只是函数™️。所以解耦更容易。将它们拉入其他文件,将它们导入回组件内部使用,只要适合您。我不认为保持东西干净是钩子的问题。
-
我明白了,我认为如果在更新状态时有一个回调并且可以在它之后运行登录,一切都会更容易
-
嗯,组件函数体本身保证在每次更新后运行……所以不太确定你想要什么。还有更具体的吗?
-
顺便说一句,我认为与 Glen 您当前的代码 LGTM 相似。除了我不会把所有这些函数都塞进组件函数之外,看起来很拥挤。但是代码本身很好。
-
@hackape 我明白了,所以任何额外的功能和逻辑都应该放在单独的文件夹中
标签: reactjs