使用ConnectedRouter+push实现重定向遇问题:mapStateToProps报错、视图不更新
Hey there! Let’s tackle those two frustrating issues you’re hitting with ConnectedRouter and redirects using push. I’ve dealt with these exact problems before, so let’s walk through the most common fixes step by step.
Issue 1: mapStateToProps Throws Errors
First up, let’s troubleshoot the mapStateToProps errors. These almost always boil down to missing or misconfigured Redux/ConnectedRouter integration:
- Make sure ConnectedRouter is wrapped inside Redux Provider: Your entire ConnectedRouter component tree needs access to the Redux store via the Provider. If ConnectedRouter is outside the Provider, components using
connectwon’t find the store context, leading to errors. - Verify your root reducer includes the router slice: You must use
connectRouter(history)to create the router reducer and include it in your combined reducers. If this is missing, mapStateToProps won’t be able to accessstate.router(or whatever key you assigned it) without throwing an error. - Double-check state paths in mapStateToProps: If you’re trying to access something like
state.router.location, make sure you didn’t misspell the router reducer key (e.g., usingstate.routeinstead ofstate.router). - Confirm you’re using the correct
connectimport: Ensure you’re importingconnectfromreact-redux, not any other library.
Issue 2: URL Changes But View Doesn’t Update
This is a super common gotcha with ConnectedRouter—usually caused by inconsistent history instances or missing middleware:
- Use a single history instance everywhere: The history object you pass to
ConnectedRoutermust be the exact same one used to create therouterMiddlewareandconnectRouterreducer. If you create separate instances (e.g., one in your store file, another in your App component), the router won’t sync properly with the store, leading to URL-only updates. - Add routerMiddleware to your Redux store: Without this middleware, the
pushaction won’t be processed correctly to update the store and trigger component re-renders. It’s a required piece for ConnectedRouter to work with Redux actions. - Import push from connected-react-router: Don’t use the
pushmethod fromreact-router-domdirectly in Redux actions. You need to importpushfromconnected-react-routerand dispatch it as a Redux action—this ensures the store and router stay in sync. - Check your Route configuration: Make sure your
/welcomeroute is defined inside theConnectedRoutercomponent, wrapped in aSwitch(if needed), and that the component prop points to the correct Welcome component. A missing or misconfigured Route will mean no content renders even when the URL changes. - Ensure connected components are re-rendering: If your page components use
connect, make sure theirmapStateToPropsis correctly selecting the state that changes when the route updates (e.g.,state.router.location). If your component is a pure component and isn’t receiving new props related to the route, it won’t re-render.
Example of Correct Configuration
Let’s put this all together with a minimal working setup to compare against your code:
- Create a shared history file (e.g.,
src/history.js):
import { createBrowserHistory } from 'history'; export default createBrowserHistory();
- Root Reducer (
src/reducers/index.js):
import { combineReducers } from 'redux'; import { connectRouter } from 'connected-react-router'; import history from '../history'; // Import your other reducers here import authReducer from './auth'; const rootReducer = combineReducers({ router: connectRouter(history), auth: authReducer, // Add other reducers here }); export default rootReducer;
- Redux Store (
src/store.js):
import { createStore, applyMiddleware, compose } from 'redux'; import { routerMiddleware } from 'connected-react-router'; import rootReducer from './reducers'; import history from './history'; import thunk from 'redux-thunk'; // If you use thunk middleware // Enable Redux DevTools if available const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( rootReducer, composeEnhancers( applyMiddleware( routerMiddleware(history), // Required for ConnectedRouter thunk // Add other middleware here ) ) ); export default store;
- App Component with Routes (
src/App.js):
import React from 'react'; import { Provider } from 'react-redux'; import { ConnectedRouter } from 'connected-react-router'; import { Switch, Route } from 'react-router-dom'; import history from './history'; import store from './store'; import Welcome from './components/Welcome'; import Login from './components/Login'; function App() { return ( <Provider store={store}> <ConnectedRouter history={history}> <Switch> <Route path="/welcome" component={Welcome} /> <Route path="/" component={Login} /> </Switch> </ConnectedRouter> </Provider> ); } export default App;
- Dispatching Push in a Component:
import React from 'react'; import { connect } from 'react-redux'; import { push } from 'connected-react-router'; const Login = ({ dispatch }) => { const handleLogin = () => { // Your login logic here dispatch(push('/welcome')); }; return <button onClick={handleLogin}>Log In</button>; }; export default connect()(Login);
Go through your code and compare against these steps—odds are you’re missing one of these critical pieces, like the shared history instance or routerMiddleware.
内容的提问来源于stack exchange,提问作者Blankman

