我正在尝试使用 Express 后端在 Reactjs 和 TypeScript 中实现多项选择测验。
Lesson 组件从 API 中获取一个 Lesson 对象,其中包含每个多项选择题的字段,将当前状态设置为课程对象,然后为每个选择题呈现一个 MultipleChoiceQuestion 组件。如果答案正确与否,我将回调函数传递给他们每个人以更新分数。但是,当我调用该函数时,出现此错误:
Warning: Cannot update a component (`Lesson`) while rendering a different component (`MultipleChoiceQuestion`). To locate the bad setState() call inside `MultipleChoiceQuestion`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
MultipleChoiceQuestion@http://localhost:3000/static/js/main.chunk.js:1715:89
div
div
div
Lesson@http://localhost:3000/static/js/main.chunk.js:1473:108
Route@http://localhost:3000/static/js/vendors~main.chunk.js:34738:29
Switch@http://localhost:3000/static/js/vendors~main.chunk.js:34940:29
Router@http://localhost:3000/static/js/vendors~main.chunk.js:34373:30
BrowserRouter@http://localhost:3000/static/js/vendors~main.chunk.js:33993:35
App
Context@http://localhost:3000/static/js/main.chunk.js:2721:81 index.js:1
这是我的代码,去掉了不相关的部分
import MultipleChoiceQuestion from './MultipleChoiceQuestion'
function Lesson() {
const [lesson, setLesson] = useState<Lesson>()
const [score, setScore] = useState(0)
const [maxScore, setMaxScore] = useState<number>(0)
const [attempt, setAttempt] = useState(false)
useEffect(() => {
// fetch from api
}, [lessonID])
const getQuestionScore = (questionScore: number, questionMax: number) => {
setScore(score + questionScore)
setMaxScore(maxScore + questionMax)
}
return (
<div>
{lesson.questions.map((q: MultipleChoiceQuestion) => {
const incorrect = q.incorrect
const correct = q.correct
return <MultipleChoiceQuestion
attempt={attempt} key={q.question}
question={q.question} scoreCallback={getQuestionScore}
correct={correct} incorrect={incorrect} />
})}
<button onClick={() => setAttempt(true)} >Test</button>
<h3>{score}/{maxScore}</h3>
</div>
</div>
</div>
)}
function MultipleChoiceQuestion(props: {
correct: string[],
attempt: any, incorrect: string[],
question: string, scoreCallback: any
}) {
const [hasReturnedScore, setHasReturnedScore] = useState(false)
const handleChange = (e: any) => {
setSelected(e.target.value)
}
if (props.attempt && !hasReturnedScore) {
setHasReturnedScore(true)
const score = calculateScore()
score ? props.scoreCallback(1, 1) : props.scoreCallback(0, 1)
}
return (
<div className="container">
<h2 className="title is-6">{props.question}</h2>
{props.correct.map((choice: any) => {
return <AnswerBox key={choice} choice={choice} selected={selected} changeCallback={handleChange} />
})}
{props.incorrect.map((choice: any) => {
return <AnswerBox key={choice} choice={choice} selected={selected} changeCallback={handleChange} />
})}
)
}
const AnswerBox = (prop: any) => {
return (
<label htmlFor="question" className="column radio" >
<input
id={prop.choice}
type="radio"
value={prop.choice}
checked={prop.selected === prop.choice}
onChange={prop.changeCallback}
name="choice" />
{prop.choice}
</label>
)}
我错误地认为将数据从子组件传递给父组件是一种聪明的方法,但现在我不知道如何解决这个问题。
答案 0 :(得分:1)
你的这部分
if (props.attempt && !hasReturnedScore) {
setHasReturnedScore(true)
const score = calculateScore()
score ? props.scoreCallback(1, 1) : props.scoreCallback(0, 1)
}
目前,它是写在子组件(MultipleChoiceQuestion)的渲染上的。这是错误的,因为它仅在渲染时调用函数。 您需要在某个事件处理程序(一个在单击单选按钮等事件时调用的函数)中移动它,或者您将这个函数移动到 useEffect
钩子内。