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

在Gatsby中使用Zustand-persist结合localStorage遇构建错误求助

问题

在Gatsby应用中使用Zustand管理全局状态,其中一个状态切片通过zustand-persist同步到localStorage。依赖更新后,执行gatsby build时出现错误:

WebpackError: ReferenceError: localStorage is not defined

初始代码:

import create from 'zustand'
import { configurePersist } from 'zustand-persist';

const { persist, purge } = configurePersist({
  storage: localStorage
})

尝试修改代码,判断浏览器环境后传入localStorage:

import { create } from 'zustand'
import { configurePersist } from 'zustand-persist';

const isBrowser = typeof window !== "undefined";

const { persist, purge } = configurePersist({
  storage: isBrowser ? window?.localStorage : null, // use `AsyncStorage` in react native
  // rootKey: 'root', // optional, default value is `root`
})

但出现新错误:

TypeError: Cannot read properties of null (reading 'getItem')

想了解是否需要mock相关方法才能避免构建失败?有没有Gatsby专用的包可以处理该问题?

解决方案

1. Mock兼容的Storage对象

服务端渲染时不能传入null,需要提供一个模拟localStorage核心方法的对象,避免调用getItem等方法时触发报错:

import { create } from 'zustand'
import { configurePersist } from 'zustand-persist';

const isBrowser = typeof window !== "undefined";

// 服务端用mock对象,实现空方法避免报错
const mockStorage = {
  getItem: () => null,
  setItem: () => {},
  removeItem: () => {}
};

const { persist, purge } = configurePersist({
  storage: isBrowser ? window.localStorage : mockStorage,
})

2. 改用Zustand官方Persist中间件

zustand-persist可能存在维护不及时的问题,建议直接使用Zustand自带的persist中间件(需安装zustand/middleware),它会自动处理服务端与客户端的环境差异:

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

const useStore = create(
  persist(
    (set, get) => ({
      // 你的状态定义,比如:
      count: 0,
      increment: () => set(state => ({ count: state.count + 1 }))
    }),
    {
      name: 'app-storage', // localStorage中存储的键名
      storage: typeof window !== 'undefined' ? window.localStorage : undefined,
    }
  )
)

3. Gatsby专属延迟初始化方案

利用Gatsby的wrapRootElement钩子,在客户端挂载后再初始化带persist的状态,确保服务端渲染时不会执行localStorage相关代码:

  1. 在项目根目录创建gatsby-browser.js和gatsby-ssr.js:
// gatsby-browser.js 和 gatsby-ssr.js
import React from 'react'
import { StoreProvider } from './src/store/StoreProvider'

export const wrapRootElement = ({ element }) => {
  return <StoreProvider>{element}</StoreProvider>
}
  1. 编写状态提供者组件,仅在客户端初始化带persist的store:
// src/store/StoreProvider.js
import React, { useEffect, useState, createContext, useContext } from 'react'
import { create } from 'zustand'
import { persist } from 'zustand/middleware'

// 创建上下文
const StoreContext = createContext(null)

// 定义状态创建函数
const createAppStore = () => create(
  persist(
    (set) => ({
      // 你的状态逻辑
      count: 0,
      increment: () => set(s => ({ count: s.count + 1 }))
    }),
    { name: 'gatsby-app-store' }
  )
)

export const StoreProvider = ({ children }) => {
  const [store, setStore] = useState(null)

  useEffect(() => {
    // 仅在客户端初始化store
    setStore(createAppStore())
  }, [])

  // 服务端渲染时返回加载占位或null
  if (!store) return null

  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
}

// 自定义hook获取状态
export const useAppStore = () => useContext(StoreContext)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:24:52