React 16+React Router v4路由切换时Redux Store状态重置问题咨询
Hey there, let's break down why your Redux state is resetting and your App component is re-rendering nonstop when switching routes with React 16 + React Router v4. This is a super common gotcha, so let's walk through the fixes step by step.
1. You're probably creating a new Redux store inside your App component
This is the #1 reason for state resets on route changes. If you're initializing your store inside the App component (or any component that re-renders on route switches), every time App re-renders, you're making a brand new store with fresh initial state. That's why mapStateToProps keeps getting an empty state—you're working with a brand new store every time!
Bad Example (what you might be doing):
// App.js import { createStore } from 'redux'; import rootReducer from './reducers'; function App() { // 🔴 Creates a new store EVERY TIME App re-renders const store = createStore(rootReducer); return ( <Provider store={store}> <Switch> <Route path="/page1" component={Page1} /> <Route path="/page2" component={Page2} /> </Switch> </Provider> ); }
Fix: Move store creation outside of any component, usually in your root index.js file. This way, the store is created once when your app loads, not on every re-render.
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { BrowserRouter as Router } from 'react-router-dom'; import { createStore } from 'redux'; import rootReducer from './reducers'; import App from './App'; // ✅ Store created ONCE when the app starts const store = createStore(rootReducer); ReactDOM.render( <Provider store={store}> <Router> <App /> </Router> </Provider>, document.getElementById('root') );
2. Your <Provider> is wrapped inside the Router (or a re-mounting component)
If your Provider is nested inside the Router or any component that unmounts/mounts when routes change, it'll trigger a new store instance. The Provider needs to be the outermost component, wrapping your entire routing setup so it never unmounts.
Bad Example:
// App.js function App() { return ( <Router> <Provider store={store}> {/* 🔴 Provider is inside Router—bad news */} <Switch> <Route path="/page1" component={Page1} /> </Switch> </Provider> </Router> ); }
Fix: Keep Provider at the top level, wrapping the Router as shown in the index.js example above.
3. Double-check your reducer's initial state
Make sure your reducers are properly defining initial state. If a reducer doesn't set a default state value, it'll return undefined initially, which might look like an empty state in mapStateToProps.
Correct Reducer Example:
// reducers/yourReducer.js const initialState = { yourProperty: 'your initial value here' // ✅ Explicit initial state }; export default function yourReducer(state = initialState, action) { switch (action.type) { case 'UPDATE_PROPERTY': return { ...state, yourProperty: action.payload }; default: return state; // Always return state on unknown actions } }
4. Fix unnecessary App re-renders (optional but helpful)
Once you've fixed the store issue, if your App component is still re-rendering more than needed, you can wrap it in React.memo to prevent re-renders when props haven't changed:
// App.js import React from 'react'; import { Switch, Route } from 'react-router-dom'; const App = React.memo(() => { return ( <Switch> <Route path="/page1" component={Page1} /> <Route path="/page2" component={Page2} /> </Switch> ); }); export default App;
Quick Recap
The core issue is almost always that your store is being recreated on every route change. Moving store creation outside of components and ensuring Provider wraps your entire Router will fix the state reset and empty mapStateToProps problems.
内容的提问来源于stack exchange,提问作者Mark Romano

