(一) react-router-redux中间件
所需环境:
(1) 用creact-react-app脚手架启一个new项目
create-react-app new
(2)安装redux
cnpm install redux --save-dev
(3)安装react-redux
cnpm install react-redux --save-dev
(4)安装redux-devtools
cnpm install redux-devtools --save-dev
(5)安装react-router-dom
cnpm install react-router-dom --save-dev
(1) 安装react-router-redux
react-router-redux作用:可以把router中的location(url信息等)注入到redux中,用redux来统一管理
cnpm install react-router-redux@next --save-dev
一般会用到react-router-redux中的:
ConnectedRouter , routerReducer , routerMiddleware , push
// 这里要注意,ConnectedRouter的首字母要大写
// 注意是安装( @next版本 )
// 在两个地方会用到react-router-redux
1. 在store.js 用到routerReducer,routerMiddleware
2. 在index.js 用到ConnectedRouter
(2) 安装 history 库
history是一个JavaScript库,可让您轻松管理任何运行JavaScript的会话历史记录。用来管理历史堆栈,导航,确认导航以及在会话之间保持状态。
cnpm install history --save-dev
(2) 新建 history.js
import createHistory from 'history/createBrowserHistory';
export default createHistory();
history.js在两个地方会用到:
1.store.js 中
2.入口文件js中 (index.js)
(3) store.js
import {createStore, combineReducers, applyMiddleware} from 'redux';
import { routerReducer, routerMiddleware} from 'react-router-redux';
import username from '../component/username/reducer';
import history from '../history/history'; // 上面的history.js
import thunkMiddleware from 'redux-thunk'; // redux-thunk中间件用于dispatch一个函数
const totalReducer = {
username:username,
router:routerReducer // routerReducer
}
export const store = createStore( // 根据规则建立store
combineReducers({ // combineReducers组合多个reducer
...totalReducer
}),
window.devToolsExtension ? window.devToolsExtension() : undefined, // devTools插件
applyMiddleware(thunkMiddleware,routerMiddleware(history)) // routerMiddleware
);
export function injectAsyncReducer(name, reducer) { // 异步注入reducer
store.AsyncReducers = store.AsyncReducers || {};
if (store.AsyncReducers[name]) {
return ;
}
store.AsyncReducers[name] = reducer;
store.replaceReducer(combineReducers({ // store的api中的replaceReducer(nextReducer)方法
...totalReducer,
... store.AsyncReducers
}))
}
(4) index.js入口文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import {Provider} from 'react-redux'; //Provider的作用是保存store给子组件中的connect使用
import RouterA from './router/router';
// import {BrowserRouter} from 'react-router-dom';
import {ConnectedRouter} from 'react-router-redux'; // 引入ConnectedRouter
import history from './history/history';
import {store} from './store/store';
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}> // 使用ConnectedRouter
<App>
<RouterA/> // 路由组件,在App中用{this.props.children}引入
</App>
</ConnectedRouter>
</Provider>
, document.getElementById('root'));
registerServiceWorker();
(二) injectAsyncReducer函数 (名字是自己定义的)
作用: 实时更新的reducer
(1) replaceReducer(nextReducer)
replaceReducer(nextReducer)是redux的api中的 store 的一个函数
- 作用:替换 store 当前用来计算 state 的 reducer。
这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。在实现 Redux 热加载机制的时候也可能会用到。 - ( 我的理解是: 实时更新的reducer )
- (redux中文文档)http://www.redux.org.cn/docs/api/Store.html#replaceReducer
(2) injectAsyncReducer函数定义
store.js中
export function injectAsyncReducer(name, reducer) { // name, reducer作为参数
store.AsyncReducers = store.AsyncReducers || {}; // 存在赋值,不存在赋值空对象
if (store.AsyncReducers[name]) { // store中的AsyncReducers对象存在name属性,就返回
return ;
}
store.AsyncReducers[name] = reducer; // 不存在name属性,就赋值给name属性
store.replaceReducer(combineReducers({ // 用replaceReducer函数获得时时更新的reducer
...totalReducer,
... store.AsyncReducers // 拿到AsyncReducers对象,给combineReducers
}))
}
(2) injectAsyncReducer函数使用
container.js中
import React,{Component} from 'react';
import Username from './username';
import {bindActionCreators} from 'redux';
import * as actionTotal from './action';
import {connect} from 'react-redux';
import {injectAsyncReducer} from '../../store/store'; // 引入
injectAsyncReducer('address',require('./reducer').default); // 使用
class usernameContainer extends Component {
render() {
return (
<div>
<Username {...this.props}></Username>
</div>
)
}
}
function mapStateToProps(state) {
return {
name: state.username.username
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionTotal,dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(usernameContainer)
(三) redux-thunk中间件
作用: dispatch一个函数
- redux-thunk 支持 dispatch function,以此让 action creator 控制反转。被 dispatch 的 function 会接收 dispatch 作为参数,并且可以异步调用它。这类的 function 就称为 thunk。
(1) 安装
cnpm install redux-thunk --save-dev
(2) 引入
import {createStore, combineReducers, applyMiddleware} from 'redux';
import username from '../component/username/reducer';
import { routerReducer, routerMiddleware} from 'react-router-redux';
import history from '../history/history';
import thunkMiddleware from 'redux-thunk'; // 引入
const totalReducer = {
username:username,
router:routerReducer
}
export const store = createStore(
combineReducers({
...totalReducer
}),
window.devToolsExtension ? window.devToolsExtension() : undefined,
applyMiddleware(thunkMiddleware,routerMiddleware(history)) // 使用
);
(3) 使用
action.js
export function getImage() {
return dispatch => { // return 一个函数,dispatch函数作为参数
const p = fetch('http://image.baidu.com/channel/listjson?pn=0&rn=30&tag1=%E7%BE%8E%E5%A5%B3&tag2=%E5%85%A8%E9%83%A8&ie=utf8',{
method:'GET'
}).then(result => result.json() );
p.then(result => {
console.log(result,'result');
dispatch({ // dispatch一个action
type: actionTypes.GET_IMAGE,
payload: result
})
})
return p;
}
}
------------------------------------------------------------------------------------
reducer.js
import actionTypes from './constant';
const initialState = {
username:{
username: '重庆'
},
image:{}
}
export default function reducerA(state=initialState,action) {
switch(action.type) {
case actionTypes.GET_IMAGE:
return {
...state,
image:action.payload
}
default:
return state;
}
}
------------------------------------------------------------------------------------
container.js
import React,{Component} from 'react';
import Username from './username';
import {bindActionCreators} from 'redux';
import * as actionTotal from './action';
import {connect} from 'react-redux';
import {injectAsyncReducer} from '../../store/store';
injectAsyncReducer('address',require('./reducer').default);
class usernameContainer extends Component {
render() {
return (
<div>
<Username {...this.props}></Username>
</div>
)
}
}
function mapStateToProps(state) {
return {
name: state.username.username,
imageUrl:state.address.image.dat
// 拿到state.address.image.data命名为imageUrl,传给username.js
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionTotal,dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(usernameContainer)
------------------------------------------------------------------------------------
username.js
import React,{Component} from 'react';
export default class username extends Component {
getI = () => {
this.props.getImage();
}
goG = (item,key) => {
return (
<div key={key}>
<img src={item.image_url} alt=""/>
</div>
)
}
render() {
// console.log(this.props.imageUrl,'this.props.imageUrl');
return (
<div>
主页
<div onClick={this.getI}>
点击获得图片
</div>
<br/>
<br/>
{
this.props.imageUrl && this.props.imageUrl.map(this.goG)
}
</div>
)
}
}
参考文档:
(1) react-router-redux
https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux
(2)react-router v4 使用 history 控制路由跳转
https://segmentfault.com/a/1190000011137828
(3) redux-thunk
https://github.com/gaearon/redux-thunk