React异步Fetch数据后无法显示问题求助
问题解决思路
你的核心问题有两个:questions是普通数组而非React状态变量,修改它不会触发组件重新渲染;另外还有几个未定义的变量/函数需要补充实现。
1. 将questions改为React状态
React只有状态变量更新时才会重新渲染组件,你用普通数组questions存储数据,就算异步获取到数据并push进去,组件也不会感知到变化,自然不会更新渲染内容。
把const questions = [];改成状态变量:
const [questions, setQuestions] = useState([]);
然后在deneme函数里,不要直接push,而是通过setQuestions更新状态:
const deneme = async () => { const querySnapshot = await getDocs(collection(db, selection)); // 把查询到的文档数据转换成数组 const fetchedQuestions = querySnapshot.docs.map(doc => doc.data()); setQuestions(fetchedQuestions); setLoading(false); }
2. 补充未定义的变量与函数
代码里currentQuestion、chooseOption、nextQuestion、finishQuiz都没定义,这会导致渲染时逻辑失效,甚至报错,需要补充这些内容:
- 增加
currentQuestion状态变量,控制当前显示的题目索引:
const [currentQuestion, setCurrentQuestion] = useState(0);
- 实现
chooseOption函数,处理选项选择逻辑(示例逻辑,可根据需求调整):
const chooseOption = (optionKey) => { // 这里可以添加判断选项是否正确、更新分数等逻辑 // 比如:if(questions[currentQuestion].correct === optionKey) setScore(prev => prev + 1); }
- 实现
nextQuestion函数,切换到下一题:
const nextQuestion = () => { setCurrentQuestion(prev => prev + 1); }
- 实现
finishQuiz函数,处理测验结束逻辑:
const finishQuiz = () => { // 比如切换游戏状态、跳转到结果页等 setGameState("result"); }
3. 修复渲染时的边界判断
虽然用了可选链?.避免了报错,但最好加上边界判断,防止currentQuestion超出数组范围:
比如在加载完成后判断数组是否为空:
if (isLoading) { return <div> Loading</div> } if (questions.length === 0) { return <div>暂无题目数据</div> }
完整修正后的代码
import { useState, useContext, useEffect } from "react"; import { GameStateContext } from "../helpers/Context" import { db } from '../../firebase-config' import { collection, getDocs } from "firebase/firestore"; const Quiz = () => { const { score, setScore, gameState, setGameState, selection } = useContext(GameStateContext); const [isLoading, setLoading] = useState(true); // 改为状态变量 const [questions, setQuestions] = useState([]); // 添加当前题目索引状态 const [currentQuestion, setCurrentQuestion] = useState(0); useEffect(() => { deneme(); }, [selection]); // 依赖添加selection,当选择的集合变化时重新获取数据 const deneme = async () => { setLoading(true); // 重新获取时显示加载 const querySnapshot = await getDocs(collection(db, selection)); const fetchedQuestions = querySnapshot.docs.map(doc => doc.data()); setQuestions(fetchedQuestions); setCurrentQuestion(0); // 重置当前题目索引 setLoading(false); } // 实现选项选择函数 const chooseOption = (optionKey) => { // 示例:判断选项是否正确并更新分数 if (questions[currentQuestion]?.correct === optionKey) { setScore(prev => prev + 1); } } // 实现下一题函数 const nextQuestion = () => { if (currentQuestion < questions.length - 1) { setCurrentQuestion(prev => prev + 1); } } // 实现结束测验函数 const finishQuiz = () => { setGameState("result"); } if (isLoading) { return <div> Loading</div> } if (questions.length === 0) { return <div>暂无题目数据</div> } return ( <div className="Quiz"> <h1>{questions[currentQuestion].question}</h1> <div className="questions"> <button onClick={() => chooseOption("optionA")} > {questions[currentQuestion].optionA} </button> <button onClick={() => chooseOption("optionB")} > {questions[currentQuestion].optionB} </button> <button onClick={() => chooseOption("optionC")} > {questions[currentQuestion].optionC} </button> <button onClick={() => chooseOption("optionD")} > {questions[currentQuestion].optionD} </button> </div> {currentQuestion === questions.length - 1 ? ( <button onClick={finishQuiz} id="nextQuestion"> Finish Quiz </button> ) : ( <button onClick={nextQuestion} id="nextQuestion"> Next Question </button> )} </div> ) } export default Quiz;
内容的提问来源于stack exchange,提问作者Adonis
相关产品推荐
相关产品推荐

