正如标题所述,我正在使用 NextJS 创建一个网站,并使用 TailwindCSS 进行样式设置。然而,我的代码有一个小而烦人的问题。
下面是我的页面主要内容的代码:
"use client"
import React, {useState} from 'react';
export default function MainContent(){
const [eventTerm, setSearchTerm] = useState('');
const [zipCode, setZipCode] = useState('');
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.currentTarget.value);
}
const handleZipChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setZipCode(event.currentTarget.value);
}
const handleSubmit = (event: React.ChangeEvent <HTMLButtonElement>) => {
event.preventDefault();
// Perform search functionality here
console.log(eventTerm);
console.log(zipCode);
}
return (
<main>
<div className = "max-w-7xl mx-5 px-5 sm:px-6 lg:px-8 my-auto py-9 mt-20 text-center">
<h1 className = "font-rowdies md:text-7xl text-white sm:text-center md:text-left my-3">Test, <br/> Test </h1>
<div className = "my-auto py-5">
<small className = "font-rowdies md:text-3xl text-white md:block md:text-left my-1 flex-wrap sm:text-2xl break-words">Test</small>
<div className="my-auto py-5 md:text-left">
<form className = "relative rounded-lg bg-transparent">
<input type="text" placeholder="Find a Service" defaultValue={eventTerm} onChange={handleChange} className="form-input mr-2 py-2 px-10 rounded-md leading-5 focus:outline-none focus:shadow-outline-indigo-500 w-800 text-center font-rowdies"/>
<input type="text" placeholder="Zip Code" defaultValue={zipCode} onChange={handleZipChange} className="form-input py-2 rounded-md leading-5 focus:outline-none focus:shadow-outline-indigo-500 w-21 text-center hidden md:inline font-rowdies"/>
<button className = "bg-gray-900 text-white ml-2 px-3 py-2 rounded-md text-l font-rowdies hover:text-secondary hover:bg-white">Lets Go!</button>
</form>
</div>
</div>
</div>
</main>
)
}
我在 chrome 中遇到的错误是: 错误:水合失败,因为初始 UI 与服务器上呈现的内容不匹配。 警告:没想到服务器 HTML 中包含 .
问题似乎仅在刷新页面后才源于此行,而不是在初始加载时
<input type="text" placeholder="Zip Code" defaultValue={zipCode} onChange={handleZipChange} className="form-input py-2 rounded-md leading-5 focus:outline-none focus:shadow-outline-indigo-500 w-21 text-center hidden md:inline font-rowdies"/>
我这么说是因为每当我删除这一行时,两个错误就会消失,并且我的网站工作得很好。
除此之外,我还向我的朋友发送了该文件,并且该文件在他的计算机上运行良好。我尝试的内容包括检查我的依赖项是否是最新的,并使用我的代码清除我的缓存和 cookie 以及其他内容。
任何帮助将不胜感激。我还将添加更多代码片段以及目录结构图像。
谢谢!
主页.tsx
import React, { MouseEventHandler, useState } from 'react';
import { Disclosure, Menu, Transition } from '@headlessui/react'
import '../styles/globals.css'
import MainContent from './MainContent';
export default function (){
const [isOpen, setIsOpen] = useState(false);
return (
<>
<header>
<div className = "items-center">
<nav className = "justify-between bg-secondary">
<div className = "mx-5 px-5 sm:px-6">
<div className = "relative flex items-center justify-between h-16">
<div className = "flex flex-grow-1 flex-shrink-1">
<a href = "#" className="font-rowdies text-white text-3xl">Portfolio</a>
</div>
<div className = "hidden md:block items-end justify-end">
<div className = "ml-10 flex items-end space-x-4">
<button className = "bg-primary text-white px-3 py-2 rounded-md text-l font-rowdies hover:text-primary hover:bg-secondary">Join as a Pro</button>
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies hover:text-primary">Log In</a>
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies hover:text-primary">Sign Up</a>
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies hover:text-primary">About Us</a>
</div>
</div>
<div className="-mr-2 flex md:hidden place-content-center">
<button
onClick={() => setIsOpen(!isOpen)}
type="button"
className="bg-gray-900 inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
{!isOpen ? (
<svg
className="block h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
) : (
<svg
className="block h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
)}
</button>
</div>
</div>
</div>
<Transition
show={isOpen}
enter="transition ease-out duration-1000 transform"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75 transform"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
{(ref) => (
<div className="md:hidden text-center bg-secondary" id="mobile-menu">
<div ref={ref} className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies block hover:text-primary">Log In</a>
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies block hover:text-primary">Sign Up</a>
<a href = "#" className = " text-white px-3 py-2 rounded-md text-l font-rowdies block hover:text-primary">About Us</a>
<button className = "bg-primary text-white px-3 py-2 rounded-md text-l font-rowdies block mx-auto hover:text-primary hover:bg-secondary">Join as a Pro</button>
</div>
</div>
)}
</Transition>
</nav>
</div>
</header>
<MainContent />
</>
)
}
页面.tsx
"use client";
import Image from 'next/image'
import { Inter } from '@next/font/google'
import styles from './page.module.css'
const inter = Inter({ subsets: ['latin'] })
import { useRouter } from "next/navigation";
import Homepage from '@/components/Homepage';
import MainContent from '@/components/MainContent';
import { Main } from 'next/document';
export default function Home() {
return (
<>
<Homepage />
</>
)
}
我所有依赖项及其版本的图像
当我禁用 LastPass 浏览器扩展后,问题就消失了。 LastPass 注入 HTML 后加载,从而消除了 SSR 和客户端之间的比较。
同样的问题也出现在 Reddit 中。
一个相当优雅的解决方案 - 如果你不介意强制你的组件成为客户端组件 - 已经落地:
'use client'
import {useState, useEffect} from 'react';
import Loading from './loading'; // assumes App Router in use with loading.jsx|tsx
export default function MyComponent() {
... // other hooks, like useFormState
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) return <Loading />;
return ... // the real UI
}