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

如何创建使用Cookie、支持服务端渲染(SSR)的持久化状态Hook

问题根因

你遇到的服务端读不到Cookie、渲染不一致的核心原因是:react-cookie 的 CookiesProvider 在服务端渲染场景下无法自动获取请求头中的Cookie,需要你手动将服务端拿到的Cookie值注入到Provider中,才能让服务端运行的自定义Hook读取到正确的Cookie值。

解决方案

步骤1:修改_app.tsx,全局注入服务端Cookie

给自定义App添加getInitialProps,在服务端阶段提取请求头中的Cookie,传递给CookiesProvider作为初始值:

// src/pages/_app.tsx
import App, { AppProps, AppInitialProps } from 'next/app';
import { ThemeProvider } from 'styled-components';
import { Provider as AuthProvider } from 'next-auth/client';
import { CookiesProvider } from 'react-cookie';

import DialogContainer from '../components/shared/DialogContainer';
import { ToastsContainer } from '../components/shared/ToastsContainer';

import { ThemeContextProvider, useTheme } from '../hooks/theme';
import { DialogContextProvider } from '../hooks/dialog';
import { NormalTimerContextProvider } from '../hooks/timer/normal';
import { ToastContextProvider, useToast } from '../hooks/toast';
import { SoundContextProvider } from '../hooks/sound';

import GlobalStyle from '../styles/global';

const AppWithProviders: React.FC<AppProps & { cookies?: string }> = ({ Component, pageProps, cookies }) => {
  const { theme } = useTheme();
  const { messages } = useToast();

  return (
    <AuthProvider session={pageProps.session}>
      {/* 把服务端拿到的cookie传给CookiesProvider */}
      <CookiesProvider cookies={cookies}>
        <SoundContextProvider>
          <ThemeProvider theme={theme}>
            <DialogContextProvider>
              <NormalTimerContextProvider>
                <Component {...pageProps} />
                <GlobalStyle />
                <DialogContainer />
                <ToastsContainer messages={messages} />
              </NormalTimerContextProvider>
            </DialogContextProvider>
          </ThemeProvider>
        </SoundContextProvider>
      </CookiesProvider>
    </AuthProvider>
  );
};

const MyApp: React.FC<AppProps> = (props) => (
  <ThemeContextProvider>
    <ToastContextProvider>
      <AppWithProviders {...props} />
    </ToastContextProvider>
  </ThemeContextProvider>
);

// 新增getInitialProps获取服务端Cookie
MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext);
  const { req } = appContext.ctx;
  let cookies = '';
  // 仅服务端运行时提取Cookie
  if (req) {
    cookies = req.headers.cookie || '';
  }
  return {
    ...appProps,
    cookies,
  };
};

export default MyApp;

步骤2:优化usePersistedState的Cookie配置

给setCookie添加path: '/'配置,确保Cookie全站可访问,避免路径限制导致读不到:

// src/hooks/persistedState.tsx
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { useCookies } from 'react-cookie';

type Response<T> = [T, Dispatch<SetStateAction<T>>];

export default function usePersistedState<T = any>(key: string, initialState: T): Response<T> {
  const [cookies, setCookie] = useCookies([key]);

  const [state, setState] = useState<T>(() => {
    if (cookies[key]) return cookies[key];
    return initialState;
  });

  useEffect(() => {
    // 新增path配置,保证全站生效
    setCookie(key, state, { path: '/' });
  }, [key, setCookie, state]);

  return [state, setState];
}

验证

修改完成后刷新页面,服务端渲染阶段就能正确读取到Cookie中存储的主题值,不会再出现服务端渲染浅色、客户端瞬间切深色的闪烁问题,也不会有hydration不匹配的报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 03:36:03