React-Native 之 redux 與 react-redux

前言


  • 本文 有配套視頻,可以酌情觀看迎捺。
  • 文中內(nèi)容因各人理解不同,可能會有所偏差查排,歡迎朋友們聯(lián)系我討論凳枝。
  • 文中所有內(nèi)容僅供學習交流之用,不可用于商業(yè)用途跋核,如因此引起的相關法律法規(guī)責任岖瑰,與我無關,如文中內(nèi)容對您造成不便砂代,煩請聯(lián)系 277511806@qq.com 處理蹋订,謝謝。
  • 轉(zhuǎn)載麻煩注明出處刻伊,謝謝露戒。

redux簡介


  • 簡單來說,redux 就是幫我們統(tǒng)一管理了 react 組件的 state 狀態(tài)捶箱。

  • 為什么要使用 redux 統(tǒng)一管理 state 呢智什?沒有 redux 我們依舊可以開發(fā) APP,但是當 APP 的復雜度到達一定程度的時候丁屎,擺在我們面前的就是 難以維護 的代碼(其中包含組件大量的異步回調(diào)荠锭,數(shù)據(jù)處理等等),但是使用 redux 也會增加我們整個項目的復雜度悦屏,這就需要我們在兩者之間進行權(quán)衡了,對于這一部分键思,redux 開發(fā)者給我們下面幾個參考點:

    • 以下幾種情況不需要使用 redux

      • 整體 UI 很簡單础爬,沒有太多交互。

      • 不需要與服務器進行大量交互吼鳞,也沒有使用 WebSocket看蚜。

      • 視圖層只從單一來源獲取數(shù)據(jù)。

    • 以下幾種情況可考慮使用 redux

      • 用戶的交互復雜赔桌。

      • 根據(jù)層級用戶劃分功能供炎。

      • 多個用戶之間協(xié)作。

      • 與服務器大量交互疾党,或使用了 WebSocket音诫。

      • 視圖層需要從多個來源獲取數(shù)據(jù)。

      • 遇到 React 無法解決的問題雪位。

    • 總結(jié)以上內(nèi)容:redux 適用于 多交互竭钝,多數(shù)據(jù)源,復雜程度高的工程中。

  • 也就是說香罐,當我們的組件出現(xiàn) 某個狀態(tài)需要共享卧波,需要改變另一個組件狀態(tài) 等傳值比較不容易的情況。就可以考慮 redux 庇茫,當然還有其他 redux 的替代產(chǎn)品供我們使用港粱。

譯注:

WebSocket:被稱為下一代客戶端與服務端的異步通信方法。取代了單個的TCP套接字旦签,使用ws或wss協(xié)議查坪,可用于任意的客戶端和服務器程序。WebSocket目前由W3C進行標準化顷霹。主要的優(yōu)點是服務器和客戶端可以彼此相互推送信息咪惠,允許跨域通信。

redux 必要知識


  • 使用 redux 之前淋淀,基本的東西還是要都懂的遥昧,數(shù)據(jù)流向介紹:
redux工作流程.png
  • Action:行為。它的作用就是將我們更新組件的 狀態(tài)(state) 的每個動作抽象為一個行為朵纷,它有一個必須的參數(shù) type炭臭,定義了 Action(行為) 的名稱,其他參數(shù)可自定義袍辞。寫法:

        {
            type: 'TEST_ACTION',
            key1: 'value',
                ...
            keyN: value
        }
    
  • 因為 Action 是個對象鞋仍,所以,我們需要創(chuàng)建這個對象搅吁,那創(chuàng)建這個對象的方法叫做 ActionCreator威创,寫法:

        function testAction(key1: ?string, ..., keyN: ?string) {
            return {
                type: "TEST_ACTION",
                key1: key1,
                ...
                keyN: keyN
            }
        }
    
  • Reducer:reducer 的作用就是根據(jù)傳入的 Action行為和舊的 state對象,返回一個新的 state 谎懦,然后組件會根據(jù) state 刷新肚豺。當我們確定了組件的 state 對象結(jié)構(gòu) 和 action 行為的時候就可以編寫 reducer 中的內(nèi)容。寫法:

        function testReducer(state, action) {
            let key1 = action.key1;
            switch(action.type) {
                case TEST_ACTION:
                    return {
                    ...state,
                    key1: key1 + '變化'
                };
                
                default:
                    return state;
            }
        };
        
        export default testReducer;
    
  • 當然我們的工程中可能會有多個 reducer 的情況界拦,通過 combineReducers 可以將多個 reducer 合成統(tǒng)一管理吸申。

        import { combineReducers } from 'redux';
        import testReducer1 from './testReducer1';
        import testReducer2 from './testReducer2';
        
        export default = combineReducers({
            testReducer1,
            testReducer2
        });
    
  • reducer 是一個純函數(shù)(同樣的輸入,必須有同樣的輸出享甸,需要遵循 3 個約束):

    • 不可修改傳入的參數(shù)截碴。

    • 一定要干凈,沒有API請求蛉威,沒有變量修改日丹,單純執(zhí)行計算,沒有特殊情況蚯嫌。

    • 調(diào)用非純函數(shù)(Date.now()聚凹、Math.random()等)割坠,每次都會得到不同結(jié)果導致數(shù)據(jù)錯誤等安全問題。

    • 當傳入的 state 與 舊state 相比沒有區(qū)別妒牙,返回的 新state也應該一摸一樣彼哼。

  • Store:當 reducer 返回了新的 state 后,這個 state 怎么傳到組件和存儲就成了問題湘今,redux 就是把這個狀態(tài)統(tǒng)一放到 store 中進行管理敢朱。

        import { createStore } from 'redux';
        const store = createStore(reducers);
    
  • 上面的代碼根據(jù) reducers 創(chuàng)建了一個 store方法集(它并不是一個對象),然后再 store 中提供一些方法供我們使用:

        // 獲取當前 state
        store.getState()
        
        // 發(fā)送action,根據(jù)我們前面 注冊的reducers 處理state
        store.dispath(action)
        
        // 替換當前 state 中的 reducer
        store.replaceReducer(nextReducer) 
        
        // 添加監(jiān)聽
        store.subscribe(listener)
    
  • 另外 redux 有 5個 全局方法:

    • createStore:創(chuàng)建一個readux store 來存儲應用中所有的state摩瞎,應用中只能存在一個 store

          createStore(reducer, [initialState],enhancer);
      
    • combineReducers:把多個reducer函數(shù)作為value的object拴签,合并成一個reducers函數(shù),然后就可以通過reducers調(diào)用各個子reducer,state 對象的結(jié)構(gòu)由傳入的多個 reducer 的 key 決定旗们。

          combineReducers(...reducers)
      
    • ...middlewares:每個 middleware 接受 store 的 dispatch 和 getState 函數(shù)作為命名參數(shù)蚓哩,并返回一個函數(shù)。

      • 該函數(shù)會被傳入被稱為 next 的下一個 middleware 的 dispatch 方法上渴,并返回一個接受 action 的新函數(shù)岸梨,這個函數(shù)可以直接調(diào)用 next(action),或者在其他需要的時刻調(diào)用稠氮,也可不調(diào)用曹阔。

      • 調(diào)用鏈的最后一個 middleware 會接受真實的 store 的 dispatch 方法作為 next 參數(shù),并結(jié)束調(diào)用鏈隔披。所以 middleware 的函數(shù)為 ({ getState, dispatch }) => next => action赃份。

      • 返回值:一個應用了 middleware 后的 store enhancer。這個store enhancer 就是一個函數(shù)奢米,并且需要應用到 createStore抓韩。它會返回一個應用了 middleware 的新 createStore。

    • bindActionCreators:把 actionCreators 轉(zhuǎn)曾擁有同名 keys 的對象鬓长,讓 dispatch 把每個 actionCreator 包裝起來谒拴,這樣就可以直接調(diào)用它們。唯一使用 bindActionCreators 的場景是需要把 actionCreator 往下傳到一個組件上痢士,卻不想讓這個組件察覺到 redux 的存在彪薛,而且不希望把 redux store 或者 dispatch 傳給它茂装。

          // actionCreators:一個 actionCreators 或 鍵值是 actionCreators 的對象
          // dispatch:一個 dispatch 函數(shù)怠蹂, 由 store 提供
          bindActionCreators(actionCreators, dispatch)
      
      • 返回值:一個與原對象類似的對象,只不過這個對象中的每個函數(shù)值都直接 dispatch action少态。如果傳入的是個函數(shù)城侧,返回的也是函數(shù)。
    • compose(...fuctions):當需要多個 store 增強器 依次執(zhí)行的時候使用它彼妻。compose 在應用常見的兩個用法:

          // 1
          let buildStore = compose(
              applymiddleware(thunk)
          )(createStore)
          
          // 2
          let initStore = compose(
              applymiddleware(thunk)
          )
      
      • 參數(shù)1(arguments):合成多個函數(shù)嫌佑。每個函數(shù)接受一個函數(shù)作為參數(shù)豆茫,然后返回一個函數(shù)。

      • 參數(shù)2(Function):從右往左把接受到的函數(shù)合成后的終極函數(shù)屋摇。

  • 可能剛接觸揩魂,還不能很好理解,這邊我們換個方式來理解炮温,如下圖:

舉個栗子.png
  • 更多關于 redux 的內(nèi)容(如 redux數(shù)據(jù)異步處理等)可前往 官方文檔 閱讀查看火脉,這邊不講這么多,只要了解上面的這些就可以了柒啤。

react-redux 需要知道的那些事


  • 終于進入正題了倦挂,為了在 react-native 中使用 redux,開發(fā)者提供了 react-redux担巩,基礎工作原理不變方援,只不過多了些方法和參數(shù),所以這邊就需要繼續(xù)了解一下涛癌,以下內(nèi)容整理自官方文檔:

  • <Provider store>:使組件層級中的 connect() 方法能夠得到 redux store犯戏。正常情況下,我們的根組件應該嵌套在 <Provider> 中才能使用 connect() 方法祖很。

    • 屬性(store):工程中唯一的 redux store笛丙。

    • 屬性(children):組件層級的根組件。

  • connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]):鏈接 react組件 和 redux store假颇。

    • 參數(shù)(mapStateToProps(state, [ownProps]): stateProps):定義了這個參數(shù)胚鸯,組件會監(jiān)聽 redux store 的變化,在任何情況下笨鸡,只要 redux store 發(fā)送變化姜钳, mapStateToProps 函數(shù)就會被調(diào)用。也就是說:mapStateToProps負責返回需要傳遞給子組件的 state形耗。

      • 這個函數(shù)必須返回一個純對象哥桥,這個對象會與組件的props合并,如果省略這個參數(shù)激涤,組件將監(jiān)聽不到 redux store 拟糕。

      • 如果指定改回調(diào)函數(shù)中的第二個參數(shù) ownProps,這個參數(shù)的值為傳遞到組件的props倦踢,而且只要組件接到新的 props送滞,mapStateToProps 也會被調(diào)用。

    • 參數(shù)(mapDispatchToProps(dispatch, [ownProps]): dispatchProps):負責返回一個 dispatchProps辱挥,dispatchProps 是actionCreator的key和dispatch(action)的組合犁嗅。

      • 如果傳遞一個對象,那么每個定義在該對象的函數(shù)都將被當做 redux action creator晤碘,而且這個對象會與 redux store 綁定在一起褂微,其中所定義的方法名將作為屬性名功蜓,合并到組件的 props 中。

      • 如果傳遞的是一個函數(shù)宠蚂,該函數(shù)將接收一個 dispatch 函數(shù)式撼,然后由我們自己決定如何返回一個對象,這個對象通過 dispatch 函數(shù)與 action creator 以某種方式綁定在一起(提示:你也許會用到 Redux 的輔助函數(shù)bindActionCreators())求厕。

      • 如果你省略這個 mapDispatchToProps 參數(shù)端衰,默認情況下,dispatch 會注入到你的組件 props 中甘改。

      • 如果指定了該回調(diào)函數(shù)中第二個參數(shù) ownProps旅东,該參數(shù)的值為傳遞到組件的 props,而且只要組件接收到新props十艾,mapDispatchToProps 也會被調(diào)用抵代。

    • 參數(shù)(mergeProps(stateProps, dispatchProps, ownProps): props (Function)):如果指定了這個參數(shù),mapStateToProps() 與 mapDispatchToProps() 的執(zhí)行結(jié)果和組件自身的 props 將傳入到這個回調(diào)函數(shù)中忘嫉。該回調(diào)函數(shù)返回的對象將作為 props 傳遞到被包裝的組件中荤牍。你也許可以用這個回調(diào)函數(shù),根據(jù)組件的 props 來篩選部分的 state 數(shù)據(jù)庆冕,或者把 props 中的某個特定變量與 action creator 綁定在一起康吵。如果你省略這個參數(shù),默認情況下返回 Object.assign({}, ownProps, stateProps,dispatchProps) 的結(jié)果访递。

    • 參數(shù)(options (Object)) 如果指定這個參數(shù)晦嵌,可以定制 connector 的行為。

      • [pure = true] (Boolean): 如果為 true拷姿,connector 將執(zhí)行 shouldComponentUpdate 并且淺對比mergeProps 的結(jié)果惭载,避免不必要的更新,前提是當前組件是一個“純”組件响巢,它不依賴于任何的輸入或 state 而只依賴于 props 和 Redux store 的 state描滔。默認值為 true。
      • [withRef = false] (Boolean): 如果為 true踪古,connector 會保存一個對被包裝組件實例的引用含长,該引用通過 getWrappedInstance() 方法獲得。默認值為 false伏穆。
    • 返回值:根據(jù)配置信息拘泞,返回一個注入了 state 和 action creator 的 React 組件。

      • 靜態(tài)屬性:WrappedComponent (Component): 傳遞到 connect() 函數(shù)的原始組件類蜈出。

      • 靜態(tài)方法:組件原來的靜態(tài)方法都被提升到被包裝的 React 組件田弥。

      • 實例方法:getWrappedInstance(): ReactComponent涛酗;僅當 connect() 函數(shù)的第四個參數(shù) options 設置了 { withRef: true } 才返回被包裝的組件實例铡原。

注:

  • 函數(shù)將被調(diào)用兩次偷厦。第一次是設置參數(shù),第二次是組件與 Redux store 連接 connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)燕刻。

  • connect 函數(shù)不會修改傳入的 React 組件只泼,返回的是一個新的已與 Redux store 連接的組件,而且你應該使用這個新組件卵洗。

  • mapStateToProps 函數(shù)接收整個 Redux store 的 state 作為 props请唱,然后返回一個傳入到組件 props 的對象。該函數(shù)被稱之為 selector过蹂。參考使用 reselect 高效地組合多個 selector 十绑,并對 收集到的數(shù)據(jù)進行處理。

  • bindActionCreators 的作用就是將 Actions 和 dispatch 組合起來生成 mapDispatchToProps 需要生成的內(nèi)容酷勺。

  • 是不是又懵圈了本橙?那其實沒必要想得太復雜,只不過是組件這邊進行了2次包裝脆诉,其他并沒有太大的改變甚亭,這邊給各位客官又畫了張圖幫忙理解:
Snip20170419_1.png

使用前準備


  • 使用 redux 之前亏狰,我們還是需要配置一下是吧,很簡單偶摔,我們只需要執(zhí)行以下步驟:

    • 使用 終端 打開需要使用 redux 的工程主目錄:

          // 比如我們的
          cd Desktop/Test
      
    • 導入 redux庫

          npm install --save redux
      
    • 我喜歡直接介紹實用的暇唾,所以這邊我們要直接介紹 react-redux ,不磨磨唧唧一大堆有的沒的辰斋,所以我們還需要:

          npm install --save react-redux
      
    • 這里先不講 中間件信不,盡量不然這些東西干擾我們。

    • 好了亡呵,這樣我們就可以開始在 react-native 中 使用 redux 了抽活。

react-redux 使用


  • 既然已經(jīng)了解了redux和react-redux相關的東西,那這邊就通過一個小Demo來實際演練一下锰什,UI結(jié)構(gòu)如下:
UI結(jié)構(gòu).png
  • 首先下硕,根據(jù) redux官方文檔的示例 我們可以看出官方建議我們將組件分成 containers(容器組件)components(模塊視圖組件)汁胆、redux 三大塊梭姓。所以我們這邊文件的層級如下圖所示:
目錄結(jié)構(gòu).png
  • 接著,我們再來完成視圖部分嫩码,然后根據(jù)視圖部分確定哪些需要 redux 支持誉尖,再來生成相應的 actionreducer 文件。

    • 首先铸题,是 Main 文件铡恕,作為我們的容器組件放到 containers 文件夾內(nèi)琢感,Main 中的內(nèi)容:

          import React, { Component } from 'react';
          import {
              StyleSheet,
              Text,
              View,
              TouchableOpacity,
          } from 'react-native';
          
          export default class Main extends Component {
              render() {
                  return (
                      <View style={styles.container}>
                          {/* 需要改變的組件 */}
          
                          {/* 按鈕 */}
                          <TouchableOpacity>
                              <Text>改變文字按鈕</Text>
                          </TouchableOpacity>
                      </View>
                  );
              }
          }
      
          const styles = StyleSheet.create({
              container: {
                  flex: 1,
                  justifyContent: 'center',
                  alignItems: 'center',
                  backgroundColor: '#F5FCFF',
              },
          });
      
    • 那里面我們需要將 Text 作為視圖組件獨立出來,所以將視圖組件 TestText 放到 components 文件夾中探熔,TestText 中的內(nèi)容:

          export default class TestText extends Component {
              render() {
                  return (
                      <Text>Welcome to React Native</Text>
                  );
              }
          }
      
  • 視圖部分我們搭建完成驹针,那么我們接著就是確定需要哪些 action(行為),那前面提到了诀艰,我們是要點擊按鈕的時候讓文字發(fā)生改變柬甥,也就是說我們當前需要一個改變文字的行為,那我們就將這個行為命名為 CHANGE_TEXT,那么我們需要初始化這個 action 這個對象其垄,也就是前面我們提到的 action creator

        export const CHANGE_TEXT = 'CHANGE_TEXT';
    
        // 初始化 CHANGE_TEXT 對象
        export const changeText = (text) => {
            return {
                type: CHANGE_TEXT,
                text
            }
        };
    
  • action 文件配置完畢后苛蒲,我們就可以根據(jù)需求來編寫 reducer 文件了,reducer 文件就是起到更新 state 的作用嘛绿满,所以我們將改變 文字 的邏輯放到這里撤防,當reducer 匹配到當前的點擊行為為 CHANGE_TEXT 時,就執(zhí)行相應的操作棒口,返回一個新的 state 給我們使用寄月,如果匹配不到,那么就默認返回一個不變的新 state

        import { CHANGE_TEXT, changeText } from '../action/action';
    
        const mainReducer = (state = changeText('welcome to React Native'), action) => {
        
            const newState = state;
            const text = action.text;
        
            // 判斷 action 類型
            switch (action.type) {
                case CHANGE_TEXT:
                    return {
                        ...newState,
                        text: '改變了' + text
                    };
        
                default:
                    return {
                        ...newState,
                        text:state.text
                    }
            }
        };
        
        export default mainReducer;
    
  • 配置完 actionreducer 兩個文件后无牵,緊接著我們就可以根據(jù) reducer 來初始化 store 了:

        import Reducer from '../reducer/reducer';
        import { createStore } from 'redux';
        
        export default () => {
        
            // 根據(jù) reducer 初始化 store
            const store = createStore(Reducer);
        
            return store;
        }
    
  • redux 的東西已經(jīng)都配置完成了漾肮,接著就剩下使用了,所以接下來要解決的問題就是怎么發(fā)送行為茎毁,怎么接收 state(狀態(tài))克懊,上面提到了,store 其實是個方法集七蜘,我們的 發(fā)送行為 和 接收狀態(tài) 方法都在 store 中谭溉,所以只要拿到 store,所以只要拿到 store 就能進行這兩個操作橡卤。

  • 那怎么拿到 store 呢扮念?在官方文檔中,清楚地告訴我們碧库,Provider 的任務就是將 store 傳給 connect柜与,而 connect 的作用是將我們的組件進行第二次包裝,將操作數(shù)據(jù)的函數(shù)和數(shù)據(jù)的狀態(tài)包裝到 props 中嵌灰,所以弄匕,首先,我們需要對我們的 Main 文件進行第一次包裝沽瞭,我們再新建一個 index 文件來對 Main 文件進行包裝:

        import React, { Component } from 'react';
    
        // 引用外部文件
        import { Provider } from 'react-redux';
        import Main from './Main';
        import configureStore from '../redux/store/store';
        
        // 調(diào)用 store 文件中的 mainReducer常量中保存的方法
        const store = configureStore();
        
        export default class Root extends Component {
            render() {
                return(
                    // 第一層包裝,為了讓 main 能夠拿到 store
                    <Provider store={store}>
                        <Main />
                    </Provider>
                )
            }
        }
    
  • 包裝完成后迁匠,我們的 Main 文件就可以獲得 store 了,那接著就是進行第二次包裝了,通過 connect 生成新組件:

        import React, { Component } from 'react';
        import {
            StyleSheet,
            Text,
            View,
            TouchableOpacity,
        } from 'react-native';
        
        
        import { connect } from 'react-redux';
        import { changeText } from '../redux/action/action';
        import TestText from '../components/TestText';
        
        
        class Main extends Component {
            render() {
        
                // 通過 props 拿到保存的 onChangeText
                const { onChangeText } = this.props;
        
                return (
                    <View style={styles.container}>
                        {/* 需要改變的組件 */}
                        <TestText {...this.props} />
        
                        {/* 按鈕 */}
                        <TouchableOpacity
                            onPress={onChangeText}
                        >
                            <Text>改變文字按鈕</Text>
                        </TouchableOpacity>
                    </View>
                );
            }
        }
        
        const styles = StyleSheet.create({
            container: {
                flex: 1,
                justifyContent: 'center',
                alignItems: 'center',
                backgroundColor: '#F5FCFF',
            },
        });
        
        // 獲取 state 變化
        const mapStateToProps = (state) => {
            return {
                // 獲取 state 變化
            }
        };
        
        // 發(fā)送行為
        const mapDispatchToProps = (dispatch) => {
            return {
                // 發(fā)送行為
            }
        };
        
        // 進行第二層包裝,生成的新組件擁有 接收和發(fā)送 數(shù)據(jù)的能力
        export default connect(mapStateToProps, mapDispatchToProps)(Main);
    
  • 到這里城丧,我們的 新組件 就能夠收發(fā)數(shù)據(jù)了延曙,那怎么接收和發(fā)送呢,別急芙贫,我們接著就來完成 mapStateToProps(更新回調(diào)) 和 mapDispatchToProps(發(fā)送行為) 兩個方法。首先傍药,我們需要通過 mapDispatchToProps 來發(fā)送行為磺平,然后通過 mapStateToProps 來監(jiān)聽 state 的變化,這邊我們需要發(fā)送的行為 typeCHANGE_TEXT,當發(fā)送行為之后国夜,reducer 就會去匹配 行為的類型谆甜,進行相應操作:

        // 發(fā)送行為
        const mapDispatchToProps = (dispatch) => {
            return {
                onChangeText: () => dispatch(changeText('外部傳值')),
            }
        };
    
  • reducer 接收到我們觸發(fā)的 行為 并進行一系列處理后克蚂,最終會返回一個新的 state,那么 就會自動調(diào)用 mapStateToProps 來告訴系統(tǒng)菠劝,state 被操作了,那么我們就可以通過 mapStateToProps 來獲取 state 狀態(tài):

        // 獲取 state 變化
        const mapStateToProps = (state) => {
            return {
                value: state.text,
            }
        };
    
  • 那么接下來我們 怎么改變文字 呢睁搭?前面提到赶诊,connect 作用就是生成一個新的組件,新的組件的 props 中包含了數(shù)據(jù)獲取和操作數(shù)據(jù)的函數(shù)园骆,所以我們需要讓 子組件拿到容器組件中的 props舔痪,然后在 子組件 中通過 props 就可以拿到上面 定義的 value 和 onChangeText:

        export default class TestText extends Component {
            render() {
        
                // 獲取 props 中的 value
                const { value } = this.props;
        
                return (
                    // 根據(jù) value 改變內(nèi)部文字
                    <Text>{value}</Text>
                );
            }
        }
    
  • 到這里,我們就能成功改變文字了锌唾。

效果演示.gif

小結(jié)論

  • 其實從上面的 demo 就可以看出锄码,使用了 redux 的項目變得比原本要復雜得多,原本幾句代碼就能搞定的事情現(xiàn)在要來個 山路十八彎 晌涕,這是因為 redux 是為了解決復雜工程而孕育的滋捶,所以不要為了使用 redux 而去使用它,使用之前需要權(quán)衡一下利弊余黎,其中的好與壞只能自己慢慢體會重窟。

  • redux 對于剛?cè)腴T的朋友來說確實比較繞,幫助理解的辦法就是多練惧财,如果只看的話可能會越看越亂亲族,所以還是建議多練,熟練之后就感覺沒什么了可缚。

中間件


  • 我個人認為 中間件 只需要注意 “順序” 就可以了霎迫。使用方法什么的在 中間件的說明文檔 中都講得很清楚。

  • 關于 中間件 的使用帘靡,這邊就不多講了知给,因為可用的 中間件 很多,不可能一個一個講,等后面文章涉及哪些 中間件 再講涩赢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末戈次,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子筒扒,更是在濱河造成了極大的恐慌怯邪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件花墩,死亡現(xiàn)場離奇詭異悬秉,居然都是意外死亡,警方通過查閱死者的電腦和手機冰蘑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門和泌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人祠肥,你說我怎么就攤上這事武氓。” “怎么了仇箱?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵县恕,是天一觀的道長。 經(jīng)常有香客問我剂桥,道長弱睦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任渊额,我火速辦了婚禮况木,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旬迹。我一直安慰自己火惊,他們只是感情好,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布奔垦。 她就那樣靜靜地躺著屹耐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪椿猎。 梳的紋絲不亂的頭發(fā)上惶岭,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音犯眠,去河邊找鬼按灶。 笑死,一個胖子當著我的面吹牛筐咧,可吹牛的內(nèi)容都是我干的鸯旁。 我是一名探鬼主播噪矛,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铺罢!你這毒婦竟也來了艇挨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤韭赘,失蹤者是張志新(化名)和其女友劉穎缩滨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泉瞻,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡脉漏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓦灶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸠删。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡抱完,死狀恐怖贼陶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巧娱,我是刑警寧澤碉怔,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站禁添,受9級特大地震影響撮胧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜老翘,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一芹啥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铺峭,春花似錦墓怀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莉炉,卻和暖如春钓账,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背絮宁。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工梆暮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绍昂。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓惕蹄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卖陵,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

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