connected-react-router
npm connected-react-router -S
- 可以通过向仓库派发动作的方式实现路由跳转。
- 每次路径发生变化时可以把最新的路径放到仓库里面,以便随时在仓库中获取。
使用
Step 1
创建一个唯一的
history
对象。
//history.tsx
import {createHashHistory} from 'history';
export default createHashHistory();
step 2
添加
routerMiddleware
中间件。
import {createStore,applyMiddleware} from 'redux';
import { routerMiddleware } from 'connected-react-router'
import rootReducer from './reducers';
import history from '../history';
let store = applyMiddleware(routerMiddleware(history))(createStore)(rootReducer);
export default store;
Step 3
在reducers里添加
connectRouter
;
// store/reducers/index.tsx
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import history from '../../history';
let reducers = {
//...
router: connectRouter(history)
}
export default combineReducers(reducers);
Step 4
把
Route
替换为ConnectedRouter
。
//index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { HashRouter as Router, Route } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import Home from './components/Home';
import store from './store';
import history from './history';
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<Route path='/' exact component={Home} />
{/*...*/}
</ConnectedRouter>
</Provider>
, document.getElementById('root'));
Step 5
添加action,使用
push
返回action对象。
//store/actions/counter.tsx
import {push} from 'connected-react-router';
export default {
goto(path:string,state?:any){
return push(path,state);
}
}
原理
index.tsx
import connectRouter from './connectRouter';
import push from './push';
import ConnectedRouter from './ConnectedRouter';
import routerMiddleware from './routerMiddleware';
export {
ConnectedRouter,
connectRouter,
routerMiddleware,
push
}
export * from './types';
types.tsx
export const REDUX_PUSH: '@@REDUX_PUSH' = '@@REDUX_PUSH';
export const REDUX_CHANGE: '@@REDUX_CHANGE' = '@@REDUX_CHANGE';
push.tsx
import { REDUX_PUSH } from './';
export default function (...args: any[]) {
return {
type: REDUX_PUSH,
payload: {
method: 'push',
args: args
}
}
}
routerMiddleware.tsx
import { REDUX_PUSH } from './';
import { MiddlewareAPI, AnyAction } from 'redux';
export default function (history: any) {
return (api: MiddlewareAPI) => (next: any) => (action: AnyAction) => {
if (action.type === REDUX_PUSH) {
let { method, args } = action.payload;
history[method](...args);
} else {
next(action);
}
}
}
ConnectedRouter.tsx
import React from 'react';
import { Router } from 'react-router';
import { History } from 'history';
import { ReactReduxContext } from 'react-redux';
import { REDUX_CHANGE } from '.';
export interface Props {
history: History
}
export interface State {
}
export default class extends React.Component<Props, State> {
static contextType = ReactReduxContext
unListener: any
componentDidMount() {
this.unListener = this.props.history.listen((location, action) => {
this.context.store.dispatch({
type: REDUX_CHANGE,
payload: {
location,
action
}
});
})
}
componentWillUnmount() {
this.unListener();
}
render() {
return <Router history={this.props.history}>
{this.props.children}
</Router>;
}
}
connectRouter.tsx
import { REDUX_CHANGE } from './';
import { History } from 'history';
import { AnyAction } from 'redux';
export default function (history: History) {
return function (state = {}, action: AnyAction) {
if (action.type === REDUX_CHANGE) {
return action.payload
} else {
return state;
}
}
}