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

如何在Next.js App目录项目中用SSR数据初始化Redux Store

基于Next.js App目录结构用SSR数据初始化Redux Store的方案

核心思路:服务端拉取数据后,创建Redux Store时将数据作为初始状态传入,客户端hydrate阶段复用该状态,避免重复请求。以下是具体实现步骤:

1. 改造store.ts,支持传入初始状态

修改makeStore函数,允许接收预加载状态,以此初始化Store:

import { configureStore } from '@reduxjs/toolkit';
import authReducer from './feature/auth/authSlice';
import blogsReducer from './feature/blogs/blogFetchSlice';
import userReducer from './feature/user/userSlice';

// 新增preloadedState参数,类型支持RootState的部分字段
export const makeStore = (preloadedState?: Partial<RootState>) => {
  return configureStore({
    reducer: {
      auth: authReducer,
      user: userReducer,
      blogs: blogsReducer,
    },
    preloadedState // 注入初始状态
  });
}

export type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];

2. 在blogFetchSlice.tsx中添加初始化数据的Reducer

新增同步Action,用于设置服务端获取的博客数据:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { BlogFetchAllState } from './types';
import { BlogGetData } from '../../models/BlogGet';

const blogFetchSlice = createSlice({
  name: 'blogFetchAll',
  initialState: {
    blogs: null,
    loading: false,
    error: null,
    current_blog: null
  } as BlogFetchAllState,
  reducers: {
    // 同步Action:设置初始博客数据
    setInitialBlogs: (state, action: { payload: BlogGetData[] }) => {
      state.blogs = action.payload;
      state.loading = false;
      state.error = null;
    }
  },
  extraReducers: (builder) => {
    // 保留原有异步请求处理逻辑(若存在)
    // 示例:builder.addCase(fetchAllBlogs.pending, (state) => { ... })
  }
});

export const { setInitialBlogs } = blogFetchSlice.actions;
export default blogFetchSlice.reducer;

3. 修改StoreProvider.tsx,支持接收初始状态

更新StoreProvider组件,使其能接收初始状态并初始化Store实例:

'use client'; // 标记为客户端组件(依赖React Hooks与Redux Provider)

import { useRef } from 'react';
import { Provider } from 'react-redux';
import { AppStore, makeStore, RootState } from '../lib/store';

interface StoreProviderProps {
  children: React.ReactNode;
  initialState?: Partial<RootState>;
}

const StoreProvider = ({ children, initialState }: StoreProviderProps) => {
  const storeRef = useRef<AppStore>();
  
  if (!storeRef.current) {
    // 用传入的初始状态创建Store
    storeRef.current = makeStore(initialState);
  }

  return <Provider store={storeRef.current}>{children}</Provider>;
};

export default StoreProvider;

4. 在Home.tsx中传递服务端数据给StoreProvider

利用服务端组件的特性拉取数据,构造Redux初始状态并传给StoreProvider:

import { Box, Button, Typography } from "@mui/material";
import blogsecure from "./services/blogSecure";
import { BlogGetData } from "./models/BlogGet";
import StoreProvider from './StoreProvider';

export const fetchData = async () => {
  const response = await blogsecure.get('/blogs/fetch_all');

  if (response.status !== 200) {
    throw new Error("Failed to fetch API data");
  }
  return response.data;
};

const Home = async() => {
  const blogs: BlogGetData[] = await fetchData();
  
  // 构造匹配Redux状态结构的初始数据
  const initialState = {
    blogs: {
      blogs: blogs,
      loading: false,
      error: null
    }
  };

  return (
    <StoreProvider initialState={initialState}>
      <Box sx={{ position: 'relative', height: '100%' }}>
        <Button sx={{ position: 'absolute', bottom: 16, right: 16 }}>
          Create blog
        </Button>
        {/* 可直接渲染数据,也可通过客户端组件从Redux取数 */}
        {blogs.map((blog) => <Typography key={blog.id}>{blog.title}</Typography>)}
      </Box>
    </StoreProvider>
  );
}

export default Home;

可选:客户端组件从Redux取数示例

创建客户端组件BlogList.tsx,直接从Redux Store获取初始化数据:

'use client';

import { useSelector } from 'react-redux';
import { RootState } from '../lib/store';
import { Typography } from '@mui/material';

const BlogList = () => {
  const { blogs } = useSelector((state: RootState) => state.blogs);
  
  return (
    <>
      {blogs?.map((blog) => <Typography key={blog.id}>{blog.title}</Typography>)}
    </>
  );
};

export default BlogList;

在Home.tsx中替换原渲染逻辑为<BlogList />即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 10:02:39