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

React SSR应用Redux Store不同步:getState始终返回initialState问题

Hey there, let's dig into why your Redux store is stuck returning the initialState in App.js even though SSR hydration seems to work at first glance. I've run into similar head-scratchers before, so here are the most common culprits to check across your files:

1. You're using a singleton Redux store (SSR's #1 pitfall)

In SSR, every server request needs its own isolated store instance, and the client needs to create its own store using the server's serialized initialState. If your createStore.js exports a pre-built singleton store instead of a factory function, the client will end up reusing a stale instance that never updates beyond the initial state.

Check createStore.js:

Bad (Singleton Store):

import { createStore } from 'redux';
import rootReducer from './reducers';

// This creates one store that gets reused across all server requests + client
const store = createStore(rootReducer);
export default store;

Good (Factory Function):

import { createStore } from 'redux';
import rootReducer from './reducers';

// Creates a fresh store instance every time it's called
export default function configureStore(initialState = {}) {
  return createStore(rootReducer, initialState);
}

Update server.js to create a new store per request:

import configureStore from './createStore';

app.get('*', (req, res) => {
  // Create a new store for this request
  const store = configureStore();
  
  // Fetch data and populate the store here
  // ... dispatch actions to build initialState
  
  const initialState = store.getState();
  
  const html = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  );
  
  res.send(`
    <html>
      <body>
        <div id="root">${html}</div>
        <script>window.initialState = ${JSON.stringify(initialState)}</script>
        <script src="/client.js"></script>
      </body>
    </html>
  `);
});

Update client.js to initialize with the server's state:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import configureStore from './createStore';
import App from './App';

// Create a client-side store using the server's initialState
const store = configureStore(window.initialState);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

2. You're directly importing the store in App.js instead of using React Redux's bindings

If you're importing the store directly into App.js (e.g., import store from './createStore') and calling store.getState(), you're likely referencing the wrong store instance. React Redux uses the Provider component to inject the correct store into your component tree—you need to use hooks or connect to access it.

Bad (Direct Store Import):

import store from './createStore';

function App() {
  // This references the singleton store, not the Provider-injected one
  const state = store.getState();
  return <div>{state.someValue}</div>;
}

Good (Use useSelector for Function Components):

import { useSelector } from 'react-redux';

function App() {
  // Subscribes to store updates and returns the latest state
  const currentState = useSelector(state => state);
  // Or target specific values:
  const someValue = useSelector(state => state.someValue);
  
  return <div>{someValue}</div>;
}

Good (Use connect for Class Components):

import { connect } from 'react-redux';

class App extends React.Component {
  render() {
    const { currentState } = this.props;
    return <div>{currentState.someValue}</div>;
  }
}

const mapStateToProps = state => ({
  currentState: state
});

export default connect(mapStateToProps)(App);

3. Timing issue: You're calling store.getState() too early

If you're calling store.getState() outside of your component's render cycle (e.g., at the top of App.js before the component mounts), you'll only get the initial state once—this value won't update as the store changes.

Bad (Early Call):

import store from './createStore';

// This runs once when the module loads, never updates
const staticInitialState = store.getState();

function App() {
  return <div>{staticInitialState.someValue}</div>;
}

Fix: Always access state within the component's render logic using useSelector or connect—these methods automatically subscribe to store changes and update your component when state changes.

4. Hydration mismatch is silently breaking the store

Even if window.initialState looks correct, mismatched data types (e.g., Dates serialized to strings, non-serializable values) can cause React hydration to fail silently, leaving your store stuck in the initial state.

Fix serialization/deserialization issues:

In server.js, handle non-serializable values when stringifying:

const initialState = store.getState();
const serializedState = JSON.stringify(initialState, (key, value) => {
  // Convert Dates to ISO strings
  if (value instanceof Date) {
    return value.toISOString();
  }
  return value;
});

In configureStore.js, restore those values:

export default function configureStore(initialState = {}) {
  const deserializedState = JSON.parse(JSON.stringify(initialState), (key, value) => {
    // Convert ISO strings back to Dates
    if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
      return new Date(value);
    }
    return value;
  });
  return createStore(rootReducer, deserializedState);
}

Start with checking the singleton store issue—it's the most common cause of this exact problem. Then verify how you're accessing state in App.js and you should be back on track!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:31:17