export default function Page({ data1 }) {
const [bookmark, setBookmark] = useState(
typeof window !== 'undefined'
? JSON.parse(localStorage.getItem('bookmark'))
: []
);
const addToBookmark = (ayatLs) => {
setBookmark([...bookmark, ayatLs]);
};
useEffect(() => {
localStorage.setItem('bookmark', JSON.stringify(bookmark));
}, [bookmark]);
return (
<>
<div className="modal-body">
<ul>
{bookmark.map((x) => (
<li key={x.nomor}>{x.tr}</li>
))}
</ul>
</div>
</>
);
}
{data1.map((x)) => (
<div className="pb-6 flex justify-between">
<span
onClick={() => addToBookmark(x)}
className={`text-sm `}>
{x.tr}
</span>
</div>
)}
当我使用typeof window !== 'undefined'
时,Error: Hydration failed because the initial UI does not match what was rendered on the server in my code like this
。
,当我改变为localStorage.getItem('bookmark')
时,错误是localStorage is not defined
当我点击addToBookmark时,它会将数据从props data1存储到localStorage,这里没有问题,但是当我在localStorage中获取数据时,我想映射数据,出现错误
我的代码有什么问题,为什么我不能从localStorage映射数据,请帮助我解决这个问题。
问题是Next.js默认预渲染页面,这意味着它们首先在服务器上渲染,然后发送到客户端进行渲染。
根据以下条件设置状态的默认值时出现错误:typeof window !== 'undefined'
.
考虑下面的例子:
const Page = () => {
const [name, setName] = useState(typeof window !== 'undefined' ? 'Peter' : 'Rick')
return <h1>{name}</h1>
}
export default Page
这段代码将抛出Error: Text content does not match server-rendered HTML.
类型的错误如果您检查页面的源代码,您将看到服务器上呈现的名称是"Rick"而在客户端第一次渲染时,渲染的名字是"彼得"。服务器端呈现的内容和客户端首先呈现的内容之间必须匹配。
您可以做的是将localStorage
数据收集和解析逻辑移动到另一个useEffect
,并在那里设置状态。这解决了这个问题,因为useEffect
只运行在客户端,因此您将有效地匹配服务器端和客户端首先呈现的内容。
export default function Page({ data1 }) {
const [bookmark, setBookmark] = useState([])
const addToBookmark = (ayatLs) => {
setBookmark([...bookmark, ayatLs])
}
useEffect(() => {
if (bookmark.length === 0) return
localStorage.setItem('bookmark', JSON.stringify(bookmark))
}, [bookmark])
useEffect(() => {
const bookmarkFromLocalStorage = localStorage.getItem('bookmark')
const parsedBookmark =
bookmarkFromLocalStorage !== null
? JSON.parse(bookmarkFromLocalStorage)
: []
setBookmark(parsedBookmark)
}, [])
return (
<>
<div className='modal-body'>
<ul>
{bookmark.map((x) => (
<li key={x.nomor}>{x.tr}</li>
))}
</ul>
</div>
</>
)
}