React.js学习笔记(14) React-router-redux中间件 + ( Redux-thunk中间件 ) + ( injectAsyncReducer函数 )

(一) 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();

redux截图








(二) 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)

injectAsyncReducer函数效果图








(三) 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>
        )
    }
}

redux.thunk效果图

参考文档:
(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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容