休息了几周后,我做了一个React应用程序来测试我的图书馆技能。 The project is on Github,我想了解React的行为:我的某些功能组件多次重传,但我不明白为什么。
例如,我负责当前级别显示的功能组件渲染两次。为什么?
import React, {useState, useEffect} from 'react';
import Stepper from './Stepper';
import style from './style';
const Levels = ({
levelNames,
currentLevel
}) => {
const [steps, setSteps] = useState([]);
useEffect(
() => {
const output = levelNames.map(
level => ({title: level.toUpperCase()})
);
setSteps(output);
}, [levelNames]
);
return (
<section className="levelsContainer" style={style.levels}>
<Stepper stepsList={steps} activeStep={currentLevel}/>
{console.log(Date.now(), "levels")}
</section>
);
}
export default React.memo(Levels);
以同样的方式,每次更新状态时,大一类都会多次放弃。对于这种情况,我想问题是调用setState时某些状态会按值更新值,对吗?我相信setState不能同步工作,这是原因吗?我们该如何解决?
import React, { PureComponent } from 'react';
import Levels from '../Levels';
import ProgressBar from '../ProgressBar';
import Question from '../Question';
import QuizOver from '../QuizOver';
import push from '../../services/push';
import quizData from '../../assets/quizData';
import { initialState, levelNames } from '../../assets/config/gameManager';
class Quiz extends PureComponent {
constructor(props) {
super(props);
this.state = initialState;
this.storedDataRef = React.createRef();
}
getFinalScore = (
goodAnswersNb,
maxQuestions
) => goodAnswersNb / maxQuestions * 100;
loadLevel = (incrementLevel) => {
const newQuizLevel = incrementLevel ? this.state.currentQuizLevel + 1 : 0;
this.loadQuestions(newQuizLevel);
};
loadQuestions = level => {
const currentQuiz = quizData.quizz[levelNames[level]];
this.storedDataRef.current = currentQuiz;
if (currentQuiz.length >= this.state.maxQuestions) {
const questions = currentQuiz.map(({answer, ...rest}) => rest);
this.setState({
...initialState,
currentQuizLevel: level,
storedQuestions: questions,
currentQuestion: questions[0].question,
questionOptions: questions[0].options
});
}
};
handleOptions = selectedAnswer => {
this.setState({
isButtonDisabled: false,
userAnswer: selectedAnswer
});
};
submitAnswer = () => {
// compute new user score first by comparison with user current answer & good one
const goodAnswer = this.storedDataRef.current[this.state.questionId].answer;
const currentScore = this.state.userAnswer === goodAnswer
? this.state.succeeds + 1
: this.state.succeeds;
// prepare quiz end data if it is last question or update questions data
const outputData = {};
const currentQuestionId = this.state.questionId;
if(currentQuestionId === this.state.maxQuestions - 1) {
outputData.score = this.getFinalScore(
currentScore,
this.state.maxQuestions
);
outputData.isQuizOver = true;
}
else {
outputData.currentQuestion = this.state.storedQuestions[currentQuestionId +1].question;
outputData.questionOptions = this.state.storedQuestions[currentQuestionId +1].options;
outputData.userAnswer = null;
outputData.isButtonDisabled = true;
}
// update state with computed data
this.setState(prevState => ({
succeeds: currentScore,
questionId: prevState.questionId + 1,
...outputData
}));
};
componentDidMount() {
this.loadQuestions(this.state.currentQuizLevel);
push.welcome(this.props.userData.pseudo);
};
componentDidUpdate(prevProps, prevState) {
const {
questionId,
succeeds,
} = this.state;
// success/failure pop up handlers
if(questionId === prevState.questionId +1 ) {
succeeds > prevState.succeeds
? push.success()
: push.failure();
}
};
render() {
const {
currentQuizLevel,
maxQuestions,
currentQuestion,
questionOptions,
questionId,
isButtonDisabled,
userAnswer,
succeeds,
isQuizOver,
score,
minScore,
} = this.state;
return isQuizOver ? (
<QuizOver
ref={this.storedDataRef}
succeeds={succeeds}
score={score}
maxQuestions={maxQuestions}
isLastLevel={currentQuizLevel === levelNames.length -1}
loadLevel={this.loadLevel}
isSucceeded={score >= minScore}
/>
):(
<React.Fragment>
<Levels
levelNames={levelNames}
currentLevel={currentQuizLevel}
/>
<ProgressBar
currentQuestionNb={questionId + 1}
maxQuestions={maxQuestions}
/>
<Question
label={currentQuestion}
options={questionOptions}
isButtonDisabled={isButtonDisabled}
userAnswer={userAnswer}
handleOptions={this.handleOptions}
submitAnswer={this.submitAnswer}
/>
</React.Fragment>
);
}
};
export default Quiz;
是一样的吗?因为我正在使用useState和useEffect挂钩,所以它会重新渲染?
要检查组件是否重新渲染,请使用console.log渲染。这样合适吗?有更好的方法吗?
对于那些将检查整个项目的核心人士,我发布了它以获得有关我的代码风格的反馈并吸收了最佳实践,并学习了优化React应用的最佳方法,所以请放心给我你的! =)