connected-react-router是一個綁定react-router到redux的組件,來實現雙向綁定router的數據到redux store中,這么做的好處就是讓應用更Redux化,可以在action中實現對路由的操作。
這個組件的關鍵就在於使用了react-router中的一個關鍵組件,也就是ReactTraining/history,這個組件看了下文檔,作者是這么解釋的
The history library is a lightweight layer over browsers' built-in History and Location APIs. The goal is not to provide a full implementation of these APIs, but rather to make it easy for users to opt-in to different methods of navigation.
按照我的理解應該是對瀏覽器原本的history對象做了一定的增強,同時應該對ReactNative等環境做了一定的polyfill。
使用connected-react-router這個庫的關鍵點就在於創建合適的history對象
我當前connected-react-router的版本為v6,需要react router大於v4,並且react-redux大於v6,react大於v16.4.0
先看index.js
import React from 'react';
import ReactDOM from 'react-dom'; import { Provider } from 'react-redux' import configureStore, { history } from './configureStore' import { ConnectedRouter } from 'connected-react-router' import routes from './routes' const store = configureStore() ReactDOM.render( <Provider store={store}>// Provider使用context將store傳給子組件 <ConnectedRouter history={history}>//ConnectedRouter傳遞history對象作為props { routes } </ConnectedRouter> </Provider> , document.getElementById('root'));
configureStore.js提供history與store
import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'
export const history = createBrowserHistory()
export default function configureStore(preloadedState) {
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
compose
const store = createStore(
createRootReducer(history),
preloadedState,
composeEnhancer(
applyMiddleware(
routerMiddleware(history),
),
),
)
return store
}
使用createBrowserHistory()創建history。
const history = createBrowserHistory()
使用redux-devtools-extension
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
reducers/index.js
import { combineReducers } from 'redux' import { connectRouter } from 'connected-react-router' import counterReducer from './counter' const rootReducer = (history) => combineReducers({ count: counterReducer, router: connectRouter(history) }) export default rootReducer
combineReducers
方法,用於 Reducer 的拆分。你只要定義各個子 Reducer 函數,然后用這個方法,將它們合成一個大的 Reducer
reducers/counter.js

const counterReducer = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } export default counterReducer
routes/index.js
import React from 'react'
import { Route, Switch } from 'react-router'
import Counter from '../components/Counter'
import { Link } from 'react-router-dom'
const routes = (
<div>
<div>
<Link to="/">Home</Link>
<Link to="/hello">Hello</Link>
<Link to="/counter">Counter</Link>
</div>
<Switch>
<Route exact path="/" ><div>Home</div></Route>
<Route path="/hello" ><div>Hello</div></Route>
<Route path="/counter" component={Counter} />
<Route ><div>No Match</div></Route>
</Switch>
</div>
)
export default routes
components/Counter.js
import React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' import { increment, decrement } from '../actions/counter' const Counter = (props) => ( <div> Counter: {props.count} <button onClick={props.increment}>+</button> <button onClick={props.decrement}>-</button> </div> ) Counter.propTypes = { count: PropTypes.number, increment: PropTypes.func.isRequired, decrement: PropTypes.func.isRequired, } const mapStateToProps = state => ({ count: state.count, }) const mapDispatchToProps = dispatch => ({ increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), }) export default connect(mapStateToProps, mapDispatchToProps)(Counter)
actions/counter.js

export const increment = () => ({ type: 'INCREMENT', }) export const decrement = () => ({ type: 'DECREMENT', })