React简易韩语问答应用:useState/useEffect重复渲染等问题排查
React韩语问答应用问题排查与修复
问题1:控制台日志输出两次,首次为空
- 原因:
- React开发环境的严格模式会触发组件双重渲染,用于检测潜在的副作用问题,这是正常机制。
- 组件初始化时
randomOptions和question的初始值为空数组,首次渲染时状态还未被useEffect中的逻辑更新,因此日志显示空值;useEffect执行后状态更新,触发第二次渲染,日志才显示正确值。
- 解决:
- 开发环境的双重渲染无需额外处理,生产环境会自动消失。
- 给
question设置null作为初始值,避免首次渲染传递无效值给子组件。
问题2:randomOptions数组出现10个元素而非预期5个
- 原因:
- 直接修改state数组:
randomOptions.push()会修改原state数组,React要求状态不可变,直接修改会导致更新逻辑混乱。 - 多次异步更新状态:循环内反复调用
setRandomOptions,但React状态更新是异步的,循环中randomOptions始终是初始空数组,导致后续排序和赋值逻辑出错。 - 引用赋值导致重复判断失效:
previousArray = randomOptions是引用原数组,无法正确过滤重复值。
- 直接修改state数组:
- 解决:
- 在函数内部创建临时数组,完成所有随机选择和排序后,一次性调用
setRandomOptions更新状态。 - 使用数组的不可变操作(如扩展运算符),避免直接修改原state数组。
- 在函数内部创建临时数组,完成所有随机选择和排序后,一次性调用
问题3:引入return (<Question/>)
组件触发错误,state值变为undefined
return (<Question/>)- 原因:
- 初始
question为空数组,传递给子组件后Data[answer]返回undefined,访问undefined.character会抛出错误。 randomizeButtonAnswer中setQuestion(randomOptions[index])依赖异步更新的randomOptions,可能导致question被设置为undefined。
- 初始
- 解决:
- 在
Question组件中添加空值判断,避免访问无效属性。 - 使用临时数组的索引设置
question,确保值的有效性。
- 在
修正后的App.js
import './App.css'; import Data from './data/data.json'; import Header from './components/Header'; import Question from './components/Question'; import { useState, useEffect } from 'react'; function App() { const [index, setIndex] = useState(Math.floor(Math.random() * 5)); const [randomOptions, setRandomOptions] = useState([]); const [question, setQuestion] = useState(null); // 初始设为null const randomizeButtonAnswer = () => { const newOptions = []; // 生成5个不重复的随机索引 while (newOptions.length < 5) { const randomNumber = Math.floor(Math.random() * Data.length); if (!newOptions.includes(randomNumber)) { newOptions.push(randomNumber); } } // 打乱数组顺序 const shuffledOptions = [...newOptions].sort(() => Math.random() - 0.5); setRandomOptions(shuffledOptions); // 从打乱后的数组中取对应index的元素作为正确答案 setQuestion(shuffledOptions[index]); } useEffect(() => { randomizeButtonAnswer(); }, [index]) console.log('index is ' + index); console.log('randomOptions is ' + randomOptions); console.log('question is ' + question); return ( <div className="App"> <Header /> {/* 只有当question有效时才渲染组件 */} {question !== null && <Question answer={question}/>} </div> ); } export default App;
修正后的Question.js
import './Question.css'; import Data from '../data/data.json'; const Question = ({ answer }) => { // 空值判断,避免访问无效属性 if (answer === null || !Data[answer]) { return <div className="question-wrapper">加载中...</div>; } return ( <div className="question-wrapper"> <h1 className="question"><span className="highlight">{Data[answer].character}</span></h1> <span>{Data[answer].character} = {Data[answer].char_id} </span> </div> ); } export default Question;
内容的提问来源于stack exchange,提问作者SnooDucks299792
相关产品推荐
相关产品推荐

