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

NextJS 13:如何从LocalStorage等获取数据构建Context API初始状态

在Next.js 13中用LocalStorage/SessionStorage/Cookies初始化Context API状态

针对LocalStorage/SessionStorage的解决方案

直接在"use client"组件中调用localStorage会返回undefined,因为Next.js 13的客户端组件仍会经过服务端渲染初始化阶段,此时window对象不存在;用useEffect延迟更新状态又会导致页面加载时的闪烁问题。可以通过以下两种方式解决:

方式1:使用useSyncExternalStore(推荐)

这个API可以直接在客户端初始化时读取LocalStorage值,同时订阅存储变化,避免闪烁且支持多标签页同步:

'use client';

import { createContext, useContext, useSyncExternalStore, useState } from 'react';

const AppContext = createContext<{
  user: string | null;
  setUser: (user: string | null) => void;
}>({ user: null, setUser: () => {} });

// 订阅LocalStorage变化
function subscribeStorage(key: string, callback: () => void) {
  window.addEventListener('storage', callback);
  return () => window.removeEventListener('storage', callback);
}

// 获取LocalStorage值(服务端返回默认值)
function getStorageValue(key: string) {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem(key);
}

export function AppProvider({ children }: { children: React.ReactNode }) {
  // 同步LocalStorage值到组件状态
  const storedValue = useSyncExternalStore(
    (cb) => subscribeStorage('user', cb),
    () => getStorageValue('user'),
    () => null
  );

  const [user, setUser] = useState<string | null>(storedValue);

  const updateUser = (newUser: string | null) => {
    setUser(newUser);
    newUser 
      ? localStorage.setItem('user', newUser) 
      : localStorage.removeItem('user');
  };

  return (
    <AppContext.Provider value={{ user, setUser: updateUser }}>
      {children}
    </AppContext.Provider>
  );
}

export function useAppContext() {
  return useContext(AppContext);
}

方式2:懒初始化useState

如果不需要多标签页同步,也可以用懒初始化函数直接在客户端读取LocalStorage,避免服务端报错:

'use client';

import { createContext, useContext, useState } from 'react';

const AppContext = createContext<{
  user: string | null;
  setUser: (user: string | null) => void;
}>({ user: null, setUser: () => {} });

export function AppProvider({ children }: { children: React.ReactNode }) {
  // 懒初始化,仅在客户端执行
  const [user, setUser] = useState<string | null>(() => {
    if (typeof window === 'undefined') return null;
    return localStorage.getItem('user');
  });

  const updateUser = (newUser: string | null) => {
    setUser(newUser);
    newUser 
      ? localStorage.setItem('user', newUser) 
      : localStorage.removeItem('user');
  };

  return (
    <AppContext.Provider value={{ user, setUser: updateUser }}>
      {children}
    </AppContext.Provider>
  );
}

export function useAppContext() {
  return useContext(AppContext);
}

针对Cookies的解决方案

Cookies可以在服务端直接读取,因此可以从服务端组件传递初始值到客户端Context Provider,彻底避免闪烁和undefined问题:

步骤1:服务端读取Cookies(比如layout.tsx)

// app/layout.tsx(服务端组件,无需"use client")
import { cookies } from 'next/headers';
import { AppProvider } from './app-provider';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const cookieStore = cookies();
  const initialUser = cookieStore.get('user')?.value || null;

  return (
    <html lang="zh-CN">
      <body>
        <AppProvider initialUser={initialUser}>{children}</AppProvider>
      </body>
    </html>
  );
}

步骤2:客户端Context接收初始值

'use client';

import { createContext, useContext, useState } from 'react';

const AppContext = createContext<{
  user: string | null;
  setUser: (user: string | null) => void;
}>({ user: null, setUser: () => {} });

export function AppProvider({ 
  children, 
  initialUser 
}: { 
  children: React.ReactNode; 
  initialUser: string | null;
}) {
  const [user, setUser] = useState<string | null>(initialUser);

  const updateUser = (newUser: string | null) => {
    setUser(newUser);
    // 更新Cookies
    if (newUser) {
      document.cookie = `user=${newUser}; path=/; max-age=3600`;
    } else {
      document.cookie = `user=; path=/; max-age=0`;
    }
  };

  return (
    <AppContext.Provider value={{ user, setUser: updateUser }}>
      {children}
    </AppContext.Provider>
  );
}

export function useAppContext() {
  return useContext(AppContext);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:44:56