Next.js报错:文本内容与服务端渲染HTML不匹配的修复咨询
问题修复方案
错误原因分析
"Text content does not match server-rendered HTML" 错误根源是Next.js服务端渲染时生成的随机键盘数据,和客户端hydrate阶段生成的随机数据不一致。你把keyboard1、keyboard2定义在组件外部,服务端和客户端会各自执行这段代码生成不同的随机值,导致两边渲染的HTML内容不匹配。
src1、src2的作用说明
你代码里的src1、src2是冗余状态——定义了但在return里完全没用到(Image组件直接用"/" + keyboard1.name + ".jpg")。你觉得移除后功能异常,大概率是因为没同时把keyboard1、keyboard2改成状态管理,导致组件无法追踪数据变化重新渲染。
完整修复代码
import Head from 'next/head' import Image from 'next/image' import Link from 'next/link' import { Inter } from '@next/font/google' import React, { useState, useEffect } from 'react' const inter = Inter({ subsets: ['latin'] }) const initialKeebs = [ {name: "Hineybeige", votes: 0, id: 0}, {name: "Vamp", votes: 0, id: 1}, {name: "Fright Club Volume 1", votes: 0, id: 2}, {name: "Tenshi", votes: 0, id: 3}, {name: "Lilac on Black", votes: 0, id: 4}, {name: "Handarbeige", votes: 0, id: 5}, {name: "Darling", votes: 0, id: 6}, {name:"Olivia++", votes: 0, id: 7} ] // 生成两个不重复的随机键盘 const getRandomKeebPair = (keebs: typeof initialKeebs) => { let k1 = keebs[Math.floor(Math.random() * keebs.length)] let k2 = keebs[Math.floor(Math.random() * keebs.length)] while (k1.name === k2.name) { k2 = keebs[Math.floor(Math.random() * keebs.length)] } return [k1, k2] } export default function Home() { // 用状态管理键盘数据和投票数,避免全局变量导致的SSR不匹配 const [keebs, setKeebs] = useState(initialKeebs) const [keyboard1, setKeyboard1] = useState<typeof initialKeebs[0]>(() => getRandomKeebPair(initialKeebs)[0]) const [keyboard2, setKeyboard2] = useState<typeof initialKeebs[0]>(() => getRandomKeebPair(initialKeebs)[1]) // 初始化时确保两个键盘不重复 useEffect(() => { const [k1, k2] = getRandomKeebPair(keebs) setKeyboard1(k1) setKeyboard2(k2) }, []) const handleSubmit = (voteFor: 1 | 2) => { // 更新投票数,通过setKeebs触发组件重新渲染 setKeebs(prevKeebs => { return prevKeebs.map(keeb => { if (voteFor === 1 && keeb.id === keyboard1.id) { return {...keeb, votes: keeb.votes + 1} } else if (voteFor === 2 && keeb.id === keyboard2.id) { return {...keeb, votes: keeb.votes + 1} } return keeb }) }) // 生成新的随机键盘对 const [newK1, newK2] = getRandomKeebPair(keebs) setKeyboard1(newK1) setKeyboard2(newK2) } return ( <> <Head> <title>Keycap Vote</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <main className="flex min-h-screen flex-col items-center bg-gradient-to-b from-[#2e026d] to-[#15162c]"> <div className="container flex flex-col items-center gap-12 px-4 py-16 "> <h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]"> Keycap <span className="text-[hsl(280,100%,70%)]">Vote</span> App </h1> </div> <Link href="/api/auth/login">Login</Link> <div className="grid grid-cols-2 gap-4 sm:grid-cols-2 md:gap-8"> <h1 className="text-2xl font-extrabold tracking-tight text-white sm:text-[3rem] container flex flex-col items-center"> {keyboard1.name} </h1> <h1 className="text-2xl font-extrabold tracking-tight text-white sm:text-[3rem] container flex flex-col items-center"> {keyboard2.name} </h1> <button onClick={() => handleSubmit(1)} className="flex max-w-md flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"> <div className="relative aspect-video h-64 max-w-[18rem]"> <Image src={`/${keyboard1.name}.jpg`} alt={keyboard1.name} layout="fill" className="rounded-xl" /> </div> </button> <button onClick={() => handleSubmit(2)} className="flex max-w-md flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"> <div className="relative aspect-video h-64 max-w-[18rem]"> <Image src={`/${keyboard2.name}.jpg`} alt={keyboard2.name} layout="fill" className="rounded-xl" /> </div> </button> <h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[3rem] container flex flex-col items-center"> {keebs.find(k => k.id === keyboard1.id)?.votes || 0} </h1> <h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[3rem] container flex flex-col items-center"> {keebs.find(k => k.id === keyboard2.id)?.votes || 0} </h1> </div> </main> </> ) };
关键修复点
- 将
keyboard1、keyboard2和keebs都改为组件内部的状态管理,避免全局变量导致的SSR数据不一致。 - 用
useState的初始化函数和useEffect生成初始随机键盘对,确保服务端和客户端初始渲染一致。 - 更新投票数时使用
setKeebs的回调函数,保证基于最新状态更新,触发组件重新渲染。 - 移除了冗余的
src1、src2状态,直接通过keyboard1、keyboard2的name生成图片路径。
内容的提问来源于stack exchange,提问作者Alex Lofnes
相关产品推荐
相关产品推荐

