Redux

Redux是JavaScript的狀態(tài)容器般眉,它提供了可預(yù)測(cè)化的狀態(tài)管理。

Redux的核心理念:

  • Store

Store是存儲(chǔ)著數(shù)據(jù)的地方潜支,Redux應(yīng)用只有一個(gè)Store甸赃。
Redux提供createStore這個(gè)函數(shù),用來(lái)生成Store冗酿。

import {createStore} from 'redux'
  ////store(創(chuàng)建的時(shí)候需要傳入一個(gè)reducer)
 const  store  =  createStore(reducer);
function reducer(state,action){}
  • Action

所有數(shù)據(jù)的變化埠对,必須通過(guò)派發(fā)(dispatch)action來(lái)更新;
action是一個(gè)普通的JavaScript對(duì)象已烤,用來(lái)描述這次更新的type和content鸠窗;

const action1 = {
    type:  "ADD_FRIEND",
    info:  {
        name:  "boge",
        age:  20
    }
}
const action2 = {
    type:"CHANGE_NAME",
    playload:  {
        index: 0,
        newName: "bogezhenshuai"    
    }
}
  • Reducer

Reducer是一個(gè)純函數(shù);
Reducer做的事情就是將傳入的state和action結(jié)合起來(lái)生成一個(gè)新的state胯究;

//定義initialState是為了給state一個(gè)默認(rèn)值
 const  initialState = {counter: 0}
function reducer(state = initialState,action){
    switch (action.type){
      case "INCREMENT":
          return  {...state,counter:state.counter + 1}
      default:
          return state;        
  }
}

Redux的三大原則:

1.單一數(shù)據(jù)源

  • 整個(gè)應(yīng)用程序的state被存儲(chǔ)在一顆object tree中,并且這個(gè)object tree只存儲(chǔ)在一個(gè) store 中躁绸;
  • Redux并沒(méi)有強(qiáng)制讓我們不能創(chuàng)建多個(gè)Store裕循,但是那樣做并不利于數(shù)據(jù)的維護(hù)臣嚣;
  • 單一的數(shù)據(jù)源可以讓整個(gè)應(yīng)用程序的state變得方便維護(hù)、追蹤剥哑、修改硅则;

2.State是只讀的

  • 唯一修改State的方法一定是觸發(fā)action,不要試圖在其他地方通過(guò)任何的方式來(lái)修改State株婴;
  • 這樣就確保了View或網(wǎng)絡(luò)請(qǐng)求都不能直接修改state怎虫,它們只能通過(guò)action來(lái)描述自己想要如何修改state;
  • 這樣可以保證所有的修改都被集中化處理困介,并且按照嚴(yán)格的順序來(lái)執(zhí)行大审,所以不需要擔(dān)心race condition(竟態(tài))的問(wèn)題;

3.使用純函數(shù)來(lái)執(zhí)行修改

  • 通過(guò)reducer將 舊state和 actions聯(lián)系在一起座哩,并且返回一個(gè)新的State徒扶;
  • 隨著應(yīng)用程序的復(fù)雜度增加,我們可以將reducer拆分成多個(gè)小的reducers根穷,分別操作不同state tree的一部分姜骡;
  • 但是所有的reducer都應(yīng)該是純函數(shù),不能產(chǎn)生任何的副作用屿良;

Redux的使用過(guò)程

    1. 創(chuàng)建一個(gè)對(duì)象圈澈,作為我們要保存的狀態(tài):
    1. 創(chuàng)建Store來(lái)存儲(chǔ)這個(gè)state:
      創(chuàng)建store時(shí)必須創(chuàng)建reducer;
      我們可以通過(guò)store.getState來(lái)獲取當(dāng)前的state尘惧;
    1. 通過(guò)action來(lái)修改state:
      通過(guò)dispatch來(lái)派發(fā)action士败;
      通常actoin中都會(huì)有type屬性,也可以攜帶其他的數(shù)據(jù)褥伴;
    1. 修改reducer中的處理代碼
    1. 可以在派發(fā)action之前谅将,監(jiān)聽(tīng)store的變化;
import {createStore} from 'redux'
//定義initialState是為了給state一個(gè)默認(rèn)值
 const  initialState = {counter: 0}
//action
 const  action = {type:"INCREMENT"};
function reducer(state = initialState,action){
    switch (action.type){
      case "INCREMENT":
          return  {...state,counter:state.counter + 1}        
  }
}
 //store(創(chuàng)建的時(shí)候需要傳入一個(gè)reducer)
 const  store  =  createStore(reducer);
//訂閱store的修改
store.subscribe(() => {
      console.log("counter:",store.getState().counter);  //顯示counter:1
});
//派發(fā)action
store.dispatch(action);
Redux流程.png

react-redux使用

安裝react-redux----yarn add react-redux

  • 組件home.js文件
import React, { PureComponent } from 'react';

// import {connect} from '../utils/connect';
import {addAction,incAction,changeBannersAction,changeRecommendAction} from '../store/actionCreators';

import {connect} from 'react-redux';

class Home extends PureComponent {
    render() {
        return (
            <div>
                <h1>Home</h1>
                <h2>當(dāng)前計(jì)數(shù):{this.props.counter}</h2>
                <button onClick={e => this.props.increment()}>+1</button>
                <button onClick={e => this.props.addNumber(5)}>+5</button>
            </div>
        )
    }
}

const mapStateToProps = state => {
    return {
        counter: state.counter
    }
};
const mapDispatchToProps = dispatch => {
    return{
        increment: function(){
            dispatch(incAction());
        },
        addNumber: function(num){
            dispatch(addAction(num));
        }
    }
} ;

export default connect(mapStateToProps,mapDispatchToProps)(Home);

  • index.js文件
import  {Provider}  from  'react-redux';

import  store  from  './store';

ReactDOM.render{
    <Provider  store={store}>
      <App />
    </Provider>,
document.getElementById('root')
};

Redux中的異步操作

Redux中進(jìn)行異步操作需要用到中間件重慢。
官網(wǎng)推薦網(wǎng)絡(luò)請(qǐng)求的中間件是使用:redux-thunk

redux-thunk是如何做到讓我們可以發(fā)送異步的請(qǐng)求呢饥臂?

  • 在默認(rèn)情況下,在dispatch(action)中似踱,action通常是一個(gè)JavaScript的對(duì)象隅熙;
  • redux-thunk可以讓dispatch(action函數(shù)),action可以是一個(gè)函數(shù)核芽;
  • 該函數(shù)會(huì)被調(diào)用囚戚,同時(shí)傳給這個(gè)函數(shù)一個(gè)dispatch函數(shù)和getState函數(shù);
    1.dispatch函數(shù)用于我們之后再次派發(fā)action轧简;
    2.getState函數(shù)考慮到我們之后的一些操作需要依賴原來(lái)的狀態(tài)驰坊,用于讓我們可以獲取之前的一些狀態(tài);

使用redux-thunk

1. 安裝redux-thunk
\triangleright yarn add redux-thunk
2. 創(chuàng)建store時(shí)傳入應(yīng)用middleware的enhance函數(shù)
\triangleright 通過(guò)applyMiddleware來(lái)結(jié)合多個(gè)Middleware哮独,返回一個(gè)enhancer拳芙;
\triangleright 將enhancer作為第二個(gè)參數(shù)傳入到createStore中察藐;

  • ./store/index.js文件
    import {createStore,applyMiddleware} from 'redux';
    import thunkMiddleware from 'redux-thunk';

    const  enhancer = applyMiddleware(thunkMiddleware);
    const  store = createStore(reducer,enhancer);

3. 定義返回一個(gè)函數(shù)的action
\triangleright 注意:這里不是返回一個(gè)對(duì)象,而是一個(gè)函數(shù)舟扎;
\triangleright 該函數(shù)在dispatch之后被執(zhí)行分飞;

  • ./store/actionCreators.js文件
    const  getHomeMultidataAction  =  ()  =>  {
      return  (dispatch)  =>  {
        axios.get("http://127.207.32.32:8000/home/multidata").then(res  => {
            const  data  =  res.data.data;
            dispatch(changeBannersAction(data.banner.list));
            dispatch(changeRecommendsAction(data.recommend.list));
        })
      }
    }

使用redux-saga

redux-saga是另一個(gè)比較常用在redux發(fā)送異步請(qǐng)求的中間件,它的使用更加的靈活睹限。

1. 安裝redux-saga
\cdot yarn add redux-saga
2. 集成redux-saga中間件
\triangleright 導(dǎo)入創(chuàng)建中間件的函數(shù)譬猫;
\triangleright 通過(guò)創(chuàng)建中間件的函數(shù),創(chuàng)建中間件羡疗,并且放到applyMiddleware函數(shù)中染服;
\triangleright 啟動(dòng)中間件的監(jiān)聽(tīng)過(guò)程,并且傳入要監(jiān)聽(tīng)的saga顺囊;

import createSageMiddleware from 'redux-saga';
import {createStore,applyMiddleware} from 'redux';

const  sagaMiddleware = createSageMiddleware();
const  storeEnhancer = applyMiddleware(thunkMiddleware,sagaMiddleware);
const  store = createStore(reducer,enhancer);
//注意:若要運(yùn)行redux-saga中間件肌索,如下代碼
sagaMiddleware.run(saga);

3. saga.js文件的編寫

import {takeEvery,put} from 'redux-saga/effects';
import axios from 'axios';
import {
    FETCH_HOME_MULTIDATA
} from './home/constants';
import { changeBannersAction, changeRecommendAction } from './home/actionCreators';

function *fetchHomeMultidata(action) {
    const res = yield axios.get("http://123.207.32.32:8000/home/multidata");
    const banners = res.data.data.banner.list;
    const recommend = res.data.data.recommend.list;
    yield put(changeBannersAction(banners));
    yield put (changeRecommendAction(recommend));
}

function *mySaga(){
    //takeLatest takeEvery區(qū)別
    //takeLatest:依次只能監(jiān)聽(tīng)一個(gè)對(duì)應(yīng)的action
    //takeEvery:每一個(gè)都會(huì)被執(zhí)行
    yield takeEvery(FETCH_HOME_MULTIDATA,fetchHomeMultidata);
}

export default mySaga;

redux-saga常用API

方法 解釋
takeEvery 可以傳入多個(gè)監(jiān)聽(tīng)的actionType,每一個(gè)都可以被執(zhí)行
takeLatest 依次只能監(jiān)聽(tīng)一個(gè)action
put 在saga中派發(fā)action不再通過(guò)dispatch特碳,而是用過(guò)put
all 可以在yield的時(shí)候put多個(gè)action
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诚亚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子午乓,更是在濱河造成了極大的恐慌站宗,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件益愈,死亡現(xiàn)場(chǎng)離奇詭異梢灭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蒸其,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門敏释,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人摸袁,你說(shuō)我怎么就攤上這事钥顽。” “怎么了靠汁?”我有些...
    開(kāi)封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵蜂大,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蝶怔,道長(zhǎng)奶浦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任踢星,我火速辦了婚禮澳叉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己耳高,他們只是感情好扎瓶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布所踊。 她就那樣靜靜地躺著泌枪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秕岛。 梳的紋絲不亂的頭發(fā)上碌燕,一...
    開(kāi)封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音继薛,去河邊找鬼修壕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遏考,可吹牛的內(nèi)容都是我干的慈鸠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼灌具,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼青团!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起咖楣,我...
    開(kāi)封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤督笆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后诱贿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體娃肿,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年珠十,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了料扰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡焙蹭,死狀恐怖晒杈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情壳嚎,我是刑警寧澤桐智,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站烟馅,受9級(jí)特大地震影響说庭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜郑趁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一刊驴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦捆憎、人聲如沸舅柜。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)致份。三九已至,卻和暖如春础拨,著一層夾襖步出監(jiān)牢的瞬間氮块,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工诡宗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滔蝉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓塔沃,卻偏偏與公主長(zhǎng)得像蝠引,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛀柴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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