connected-react-router
npm connected-react-router -S
- 可以通過向倉庫派發(fā)動作的方式實(shí)現(xiàn)路由跳轉(zhuǎn)。
- 每次路徑發(fā)生變化時可以把最新的路徑放到倉庫里面,以便隨時在倉庫中獲取。
使用
Step 1
創(chuàng)建一個唯一的
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;
}
}
}