You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js中使用localStorage且避免Hydration错误?

解决Next.js中localStorage使用的Hydration错误问题

核心原因

Next.js服务端渲染(SSR)阶段不存在window和localStorage对象,直接调用会触发localStorage is not defined错误;但如果在组件渲染流程中加入window存在性判断,服务器端与客户端渲染的UI结构会出现差异,进而触发Hydration failed because the initial UI does not match what was rendered on the server错误。

解决方案

1. 用useEffect执行localStorage操作

useEffect的回调仅在客户端渲染完成后执行,完全避开服务端渲染阶段,不会产生Hydration不匹配问题。

示例代码:

import { useEffect } from 'react';

function YourComponent() {
  useEffect(() => {
    // 此处可安全读写localStorage
    localStorage.setItem('token', 'your-auth-token');
    const savedToken = localStorage.getItem('token');
    console.log(savedToken);
  }, []); // 空依赖数组确保仅执行一次

  return <div>组件内容</div>;
}

2. 封装自定义Hook管理localStorage

把localStorage的读写逻辑封装成Hook,统一处理浏览器环境判断,避免重复代码:

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(initialValue);

  useEffect(() => {
    // 客户端读取localStorage并更新状态
    const item = localStorage.getItem(key);
    if (item) {
      setStoredValue(JSON.parse(item));
    }
  }, [key]);

  const setValue = (value) => {
    // 同步更新状态与localStorage
    setStoredValue(value);
    localStorage.setItem(key, JSON.stringify(value));
  };

  return [storedValue, setValue];
}

// 使用示例
function AuthComponent() {
  const [token, setToken] = useLocalStorage('token', '');

  const handleLogin = () => {
    setToken('new-valid-token');
  };

  return (
    <div>
      <p>当前令牌: {token}</p>
      <button onClick={handleLogin}>登录</button>
    </div>
  );
}

3. 禁用组件的SSR(动态导入)

如果组件完全依赖浏览器环境,可通过Next.js的dynamic导入禁用服务端渲染,组件仅在客户端加载:

import dynamic from 'next/dynamic';

// 禁用SSR,组件仅在客户端渲染
const ClientOnlyComponent = dynamic(
  () => import('../components/YourComponent'),
  { ssr: false }
);

function Page() {
  return <ClientOnlyComponent />;
}

4. 标记Hydration完成状态再渲染依赖内容

若必须在渲染时读取localStorage,可通过useEffect标记Hydration完成,在此之前渲染与服务端一致的占位内容:

import { useState, useEffect } from 'react';

function TokenComponent() {
  const [isHydrated, setIsHydrated] = useState(false);
  const [token, setToken] = useState('');

  useEffect(() => {
    setIsHydrated(true);
    setToken(localStorage.getItem('token') || '');
  }, []);

  // Hydration完成前,渲染统一的占位内容
  if (!isHydrated) {
    return <div>加载中...</div>;
  }

  return <div>当前令牌: {token}</div>;
}

内容的提问来源于stack exchange,提问作者Mohamed Nabil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 04:45:32