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

Next.js的getServerSideProps调用store.getState()返回空值问题

问题核心原因

  • getServerSideProps运行在服务端,执行时机远早于客户端组件的useEffect,仅在客户端useEffect中触发的listProducts action从未在服务端执行,store默认初始状态下productList自然为空
  • 当前导出的是全局单例store,Node.js作为长期运行的服务进程,多个用户请求会共享同一个store实例,会出现不同用户数据交叉污染的严重问题
  • 服务端发起网络请求时没有相对路径上下文,当前action里写的/api/products在服务端运行时会直接报错,无法成功拿到数据
  • 组件内直接打印store.getState()为空是因为打印时机早于异步action执行完成的时机,此时state还未更新

修复步骤

1. 改造store为工厂函数

将原store.js的单例导出改为导出创建store的工厂函数,保证每次请求都生成独立的store实例:

import { combineReducers, createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
// 引入你自己的reducer
import { productListReducer, categoryListReducer } from './reducers'

export const makeStore = (preloadedState = {}) => {
  const reducer = combineReducers({
    productList: productListReducer,
    categoryList: categoryListReducer,
  })
  const middleware = [thunk]
  return createStore(
    reducer, 
    preloadedState, 
    composeWithDevTools(applyMiddleware(...middleware))
  )
}

2. 改造listProducts action兼容服务端请求

补全服务端请求的完整域名:

import axios from 'axios'

export const listProducts = () => async (dispatch) => {
    try {
        dispatch({ type: 'PRODUCT_LIST_REQUEST' })
        // 判断运行环境,服务端补全完整请求域名
        const baseUrl = typeof window === 'undefined' ? 'http://localhost:3000' : ''
        const { data } = await axios.get(`${baseUrl}/api/products`)

        dispatch({
            type: 'PRODUCT_LIST_SUCCESS',
            payload: data
        })
    } catch (error) {
        dispatch({
            type: 'PRODUCT_LIST_FAIL',
            payload: error.response && error.response.data.message
                ? error.response.data.message : error.message
        })
    }
}

3. 在getServerSideProps中手动触发异步action

在服务端创建store实例后先等待异步action执行完成,再读取state:

import { makeStore } from '../redux/store'
import { listProducts } from '../redux/actions/productActions'

export default function Home({products, error, loading}) {
  // 服务端已经返回数据,可直接使用,不需要再在useEffect中重复请求
  return (
    <>
      <Header />
      <Products loading={loading} error={error} products={products} />
      <Footer />
    </>
  )
}

export async function getServerSideProps() {
  // 每次请求新建独立store
  const store = makeStore()
  // 等待异步action执行完成
  await store.dispatch(listProducts())
  // 此时state已有数据
  const { loading, error, products } = store.getState().productList

  return {
    props: {
      // 同时返回预加载状态,供客户端store初始化复用
      preloadedState: store.getState(),
      products,
      loading,
      error
    }
  }
}

4. 改造_app.js实现客户端store hydration

用服务端返回的预加载状态初始化客户端store,避免客户端重复发起请求:

import { Provider } from 'react-redux'
import { makeStore } from '../redux/store'

export default function MyApp({ Component, pageProps: { preloadedState, ...pageProps } }) {
  const store = makeStore(preloadedState)
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:06:02