React.js學習筆記(14) React-router-redux中間件 + ( Redux-thunk中間件 ) + ( injectAsyncReducer函數(shù) )

(一) react-router-redux中間件

所需環(huán)境:

(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來統(tǒng)一管理


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的會話歷史記錄未蝌。用來管理歷史堆棧蔽午,導航易茬,確認導航以及在會話之間保持狀態(tài)。


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一個函數(shù)

const totalReducer = {
    username:username,
    router:routerReducer                                          // routerReducer        
}

export const store = createStore(                                 // 根據(jù)規(guī)則建立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函數(shù) (名字是自己定義的)

作用: 實時更新的reducer

(1) replaceReducer(nextReducer)

replaceReducer(nextReducer)是redux的api中的 store 的一個函數(shù)

  • 作用:替換 store 當前用來計算 state 的 reducer抽莱。
    這是一個高級 API。只有在你需要實現(xiàn)代碼分隔骄恶,而且需要立即加載一些 reducer 的時候才可能會用到它食铐。在實現(xiàn) Redux 熱加載機制的時候也可能會用到。
  • ( 我的理解是: 實時更新的reducer )
  • (redux中文文檔)http://www.redux.org.cn/docs/api/Store.html#replaceReducer

(2) injectAsyncReducer函數(shù)定義

store.js中


export function injectAsyncReducer(name, reducer) {     // name, reducer作為參數(shù)
    store.AsyncReducers = store.AsyncReducers || {};    // 存在賦值僧鲁,不存在賦值空對象
    if (store.AsyncReducers[name]) {      // store中的AsyncReducers對象存在name屬性虐呻,就返回
        return ;
    }
    store.AsyncReducers[name] = reducer;   // 不存在name屬性,就賦值給name屬性
    store.replaceReducer(combineReducers({  // 用replaceReducer函數(shù)獲得時時更新的reducer
        ...totalReducer, 
        ... store.AsyncReducers  // 拿到AsyncReducers對象寞秃,給combineReducers
    }))
}


(2) injectAsyncReducer函數(shù)使用

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函數(shù)效果圖








(三) redux-thunk中間件

作用: dispatch一個函數(shù)

  • redux-thunk 支持 dispatch function斟叼,以此讓 action creator 控制反轉(zhuǎn)。被 dispatch 的 function 會接收 dispatch 作為參數(shù)春寿,并且可以異步調(diào)用它朗涩。這類的 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 一個函數(shù)绑改,dispatch函數(shù)作為參數(shù)
        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 控制路由跳轉(zhuǎn)
https://segmentfault.com/a/1190000011137828
(3) redux-thunk
https://github.com/gaearon/redux-thunk

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市厘线,隨后出現(xiàn)的幾起案子识腿,更是在濱河造成了極大的恐慌,老刑警劉巖造壮,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件覆履,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機硝全,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門栖雾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伟众,你說我怎么就攤上這事析藕。” “怎么了凳厢?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵账胧,是天一觀的道長。 經(jīng)常有香客問我先紫,道長治泥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任遮精,我火速辦了婚禮居夹,結果婚禮上,老公的妹妹穿的比我還像新娘本冲。我一直安慰自己准脂,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布檬洞。 她就那樣靜靜地躺著狸膏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪添怔。 梳的紋絲不亂的頭發(fā)上湾戳,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音广料,去河邊找鬼院塞。 笑死,一個胖子當著我的面吹牛性昭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播县遣,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼糜颠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了萧求?” 一聲冷哼從身側(cè)響起其兴,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎夸政,沒想到半個月后元旬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年匀归,在試婚紗的時候發(fā)現(xiàn)自己被綠了坑资。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡穆端,死狀恐怖袱贮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情体啰,我是刑警寧澤攒巍,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站荒勇,受9級特大地震影響柒莉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽翔,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一兢孝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搀擂,春花似錦西潘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至威恼,卻和暖如春品姓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箫措。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工腹备, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斤蔓。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓植酥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弦牡。 傳聞我的和親對象是個殘疾皇子友驮,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容