Redux 初見

Redux初見

本文記錄的是本身對redux的學習和理解,但願能夠簡潔易懂,入門redux,一步步的走進redux!react


Redux是什麼

ReduxJavaScript應用的狀態容器,提供可預測化的狀態管理,讓你構建一致化的應用,運行於不一樣的環境(客戶端、服務器、原生應用),而且易於測試。不只於此,它還提供超爽的開發體驗。redux

核心概念

  • store】保存應用狀態全局單一緩存

  • state】全部state以key-value的形式存儲在store服務器

  • action】描述發生什麼的對象,觸發action是惟一改變state的方式,action本質上是一個普通js對象,必必須一個type字段,值爲字符串常量網絡

  • action creator】建立actionapp

  • reducer】描述action如何改變stateide


Redux經常使用方法

createStore(reducer, [initialState])

建立一個Redux store來以存放應用中全部的state函數

combineReducers(reducers)

隨着應用複雜度上升,數據源逐漸變混亂,致使組件內部數據調用十分複雜,會產生數據冗餘或者混用等狀況,須要對reducer函數進行拆分,拆分後的每一模塊獨立負責管理state的一部分。combineReducers函數的做用是,返回一個最終的rootReducer函數,rootReducer作的事情是獲得一個由多個不一樣reducer函數做爲value(key能夠自定義)的對象。學習

const module1Reducer = combineReducers(
        module1_key1: module1_reducer1
    );
    const rootReducer = combineReducers(
        key1: reducer1,
        module1: module1Reducer
    );
    
    const store = createStore(rootReducer);
    
    // store中保存的state結構以下
    {
        key1: reducer1(state.key1, action),
        module1: {
            module1_key1: (state.module1.module1_key1, action)
        }
    }

總結一下,state對象的結構由傳入的多個reducer的key決定,能夠根據模塊拆分的細粒度,考慮是否須要嵌套使用combineReducers,整個應用的數據大體分來兩類:普通data和ui狀態測試

+ data
        - 服務器響應的數據
        - 緩存數據
        - 本地還沒有持久化到服務器的數據
        - 用戶輸入
        - ...
    + ui狀態
        - 激活的路由
        - 被選中的Tab標籤
        - 是否顯示加載動畫
        - 分頁器狀態
        - ...

設計state結構時,儘可能把state範式化,不要存在嵌套不一樣類型的對象的狀況。把數據放到一個對象(列表)中,每一個數據用id做爲主鍵。不一樣類型的對象經過id引用數據,這樣數據發生改變的時候,只須要修改一處地方,減小數據冗餘或者混用。

applyMiddleware(...middlewares)

首先要介紹一下什麼是middlewaresmiddlewares用於包裝store.dispatch,擴展其功能,在發起action以後,到達reducer以前執行一些邏輯,有點相似是aop的一種實現。
applyMiddleware大體實現:

  • 暫存redux store提供的dispatch

  • dispatch做爲實參,傳給middleware執行以後返回的函數A

  • 執行函數A,返回包裝過的dispatch,覆蓋原來的store.dispatch

function applyMiddleware(store, middlewares) {
        middlewares = middlewares.slice()
        middlewares.reverse()
        // 暫存dispatch
        let dispatch = store.dispatch
        // 包裝dispatch
        middlewares.forEach(middleware =>
            dispatch = middleware(store)(dispatch)
        )
        return {...store, { dispatch })
    }

理解了applyMiddleware的邏輯,自定義一個middleware大體以下

function(store){
        // pass store.dispatch to next 
        return function(next){
            // return dispatch
            return function(action){
                // implement middleware logic
            }
        }
    }

bindActionCreators(actionCreators, dispatch)

  • 參數actionCreators若是爲函數 把 action creators 轉成擁有同名keys的對象,但使用 dispatch 把每一個action creator包圍起來,返回新的對象

  • 參數actionCreators若是爲對象,若actionCreators[key]爲函數,用dispatch把每一個 actionCreators[key]包圍起來,返回新的對象

compose(...functions)

組合store enhance,applyMiddleware 和 redux-devtools就是store enhance


React-redux橋接

Redux自己只提供應用狀態和數據流管理,除了和React一塊兒用外,還支持其它界面庫,且沒有任何依賴。要在React的項目中使用Redux,比較好的方式是藉助react-redux這個庫來作鏈接.

provider

爲整個應用提供store數據,作的事情是把store做爲props傳遞到每個被connet()包裝的組件

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

connect(...args)(component)返回一個與Redux store鏈接的組件類,下面簡單講解一下connect方法的參數

mapStateToProps(state, [ownProps]) [Function]
  • statestore中整個應用的state

  • ownProps高階函數包裝過的組件的props

  • 該回調函數必須返回一個純對象,這個對象會與被包裝的組件的props作merge合併

  • mapStateToProps能夠作一些數據的format, filter,compose操做,保證數據在組件層面的方便使用

mapDispatchToProps(dispatch, [ownProps]) [Object or Function]
  • mapDispatchToProps參數爲Object, 每一個定義在該對象的函數都將被看成Redux action creator,其中所定義的方法名將做爲屬性名,合併到被包裝的組件的props中,實現的效果:執行component.prop.checkout()其實是dispatch了一個action,這樣作的好處是component與redux的解耦,component根本不知道redux的存在。

// action creator返回對象 
    mapDispatchToProps = {
        // action creator
        checkout: function actionCreator(productId){
            return {
                    type: types.ADD_TO_CART,
                    productId
              }    
        }
    }
    // action creator返回函數,thunk
    mapDispatchToProps = {
        // action creator
        checkout: function actionCreator(productId){
            action creator 返回一個thunk, thunk的參數爲 dispatch 和 getState
            return (dispatch, getState) => {
                  
                if (getState().products.byId[productId].inventory > 0) {
  
                         dispatch(addToCartUnsafe(productId))
                  
                }
            
            }
        }
    }

    // 最終被綁定的組件props
    component.props.checkout = function () {
        return dispatch(actionCreator.apply(undefined, arguments));
      }
  • mapDispatchToProps參數爲Function

mapDispatchToProps(dispatch, [ownProps]) = function(){
        return {
            checkout: () => {
                  
                dispatch(actionCreator())
        
            }
        }
    }        
    // 最終被綁定的組件.props
    component.props.checkout = function () {
            return dispatch(actionCreator.apply(undefined, arguments));
      }

    // 使用bindActionCreators
    mapDispatchToProps(dispatch, [ownProps]) = function(){
        return bindActionCreators(actionCreator, dispatch)
    }
    // 最終被綁定的組件props
    component.props.actionCreator = function () {
        return dispatch(actionCreator.apply(undefined, arguments));
      }

    // 使用 bindActionCreators
    mapDispatchToProps(dispatch, [ownProps]) = function(){
        return bindActionCreators({
            ‘checkout’: actionCreator
        }, dispatch)
    }
    // 最終被綁定的組件props
    component.props.checkout = function () {
                return dispatch(actionCreator.apply(undefined, arguments));
      }

使用redux以後應用的數據流向

dispatch(actionCreator) => Reducer => (state, action) => state

redux_data_flow_jpeg

  • 用戶操做或者網絡請求 store.dispatch(action)

  • redux store調用傳入的rootReducer

  • redux 執行所有的reducer,把每一個reducer執行獲得的結果輸出合成一個新的對象

  • store 存儲rootReducer返回的值,更新currentState

相關文章
相關標籤/搜索