Next.js SSR页面刷新重复渲染服务端数据致内容不匹配问题求助
解决Next.js SSR中随机数组导致的Hydration不匹配问题
问题根源
你当前的代码在组件顶层直接执行随机数组生成逻辑,会引发以下问题:
- 服务端SSR渲染时生成一次随机数组并输出对应HTML
- 客户端Hydration阶段再次执行这段逻辑,生成另一个不同的随机数组
两者内容不一致就触发了「Text content does not match server-rendered HTML」错误。
解决方案
方案一:在getServerSideProps中生成随机数组(推荐)
把随机数组的生成逻辑移到服务端的getServerSideProps里,传给组件的是已经生成好的固定随机数组,服务端和客户端拿到的完全一致,从根源避免内容不匹配。
修改后的代码:
const Quiz = ({ randomQuestionsArray }: { randomQuestionsArray: IQuestion[] }) => { let currentQuestion = 0; return ( <div>{randomQuestionsArray[currentQuestion]}</div> ) } export async function getServerSideProps() { const { data: questions } = await supabase.from('questions').select(); const numberOfQuestions = 5; const randomQuestionsArray: IQuestion[] = []; // 生成不重复的随机题目 const usedIndices = new Set(); while (randomQuestionsArray.length < numberOfQuestions) { const randomIndex = Math.floor(Math.random() * questions.length); if (!usedIndices.has(randomIndex)) { usedIndices.add(randomIndex); randomQuestionsArray.push(questions[randomIndex]); } } return { props: { randomQuestionsArray, }, } }
方案二:在客户端用useEffect生成(适合不需要SSR展示随机内容的场景)
如果不需要服务端渲染出随机题目内容,可以把生成逻辑放到useEffect里,确保只在客户端首次渲染后执行一次:
import { useState, useEffect } from 'react'; const Quiz = ({ questions }: { questions: IQuestion[] }) => { const [currentQuestion, setCurrentQuestion] = useState(0); const [randomQuestionsArray, setRandomQuestionsArray] = useState<IQuestion[]>([]); const numberOfQuestions = 5; useEffect(() => { const generateRandomQuestionsArray = () => { const arr: IQuestion[] = []; const usedIndices = new Set(); while (arr.length < numberOfQuestions) { const randomIndex = Math.floor(Math.random() * questions.length); if (!usedIndices.has(randomIndex)) { usedIndices.add(randomIndex); arr.push(questions[randomIndex]); } } return arr; }; setRandomQuestionsArray(generateRandomQuestionsArray()); }, [questions, numberOfQuestions]); // 渲染前判断数组是否生成完成,避免服务端渲染空内容导致的不匹配 if (randomQuestionsArray.length === 0) { return <div>Loading...</div>; } return ( <div>{randomQuestionsArray[currentQuestion]}</div> ) } export async function getServerSideProps() { const { data } = await supabase.from('questions').select(); return { props: { questions: data, }, } }
额外提示
原代码里的randomNumber变量未定义,需补充随机索引生成逻辑(比如Math.floor(Math.random() * questions.length)),同时建议加上去重逻辑,避免重复选中同一道题目。
内容的提问来源于stack exchange,提问作者Ruairidh Grass
相关产品推荐
相关产品推荐

