国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

理解redux

piapia / 1749人閱讀

摘要:假如說是士兵的話那么就是將軍,來管理士兵的狀態。對于來說,也就是一個最外層的容器,全部作為該容器組件的類似于,這樣一來發生變化,就會重新渲染整個頁面,從而達到更新的效果。得益于,每次并不用更新整個樹。規定,對外不暴露任何修改數據的接口。

redux 為什么引入redux

react來說,state可以包含內部的狀態以及業務數據,對于一個復雜的應用來說,state非常難以管理,一個model的變化可能引起另一個model的變化...依次下去,造成了難以維護的情況,別人很難一下子摸透你的state到底是怎么變得?所以需要引入一個東西來做數據管理,使數據變化變得清晰,redux做的就是這件事情。假如說react是士兵的話那么redux就是將軍,來管理士兵的狀態。

Flux與redux Flux

Flux是facebook提出的一種架構思想,與react一樣,強調的是單向數據流,由三大部分組成:

store來保存數據,一個數據對應一個store,每一個store有一個監聽器

dispatcher,含有兩個方法:

register,注冊事件

dispatch,分發一個action使store變化

view,與flux搭配不僅僅是react還可以是vue等,為當前頁面數據的一個展現,與數據保持一致

flux并不是一個mvc框架,flux沒有明確的contoller,但是卻有著一個controller-view,類似于mvvm中的vmview=vm(model))。對于react來說,也就是一個最外層的容器store全部作為該容器組件的state(類似于),這樣一來state發生變化,就會重新渲染整個頁面,從而達到更新view的效果。得益于virtual dom,每次并不用更新整個dom樹。(每次觸發重繪會先在內存中對新的dom樹和老的dom樹進行diff,把變化放入到patches中,最后統一更改)。

flux規定storestore對外不暴露任何修改數據的接口。

redux

facebook提供的flux包基本只有一個dispatcher的實現,意味著我們需要為對每一個store進行一次定義并且創建一個dispatcher實例,需要register一次,dispatch時也需要區分不同的store(聽著就麻煩)。基于flux思想的redux為我們做了簡化。

redux與Flux的區別

redux提倡的是單一數據源,也就是一個應用就有一個store,包含著許多的reducerreducer根據傳入的action來決定怎么改變當前狀態。關于redux,大家可以直接去看文檔,說的很清楚詳細,下面來看一下redux的源碼:

入口

index.jsredux的入口文件,暴露出來了redux所提供的API

export {
  createStore,           // 創建store
  combineReducers,       // 合并reducer
  bindActionCreators,   
  applyMiddleware,
  compose
}

其中還有一個isCrushed函數,其作用就是做環境的檢測,假如在非生產環境中使用了壓縮的redux,則提出警告,判斷方式也很簡單:

isCrushed.name !== "isCrushed"  // 壓縮后函數名字會變短

下面來一個一個的看redux暴露出API的實現:

compose

compose源自于函數式編程,redux將其用于用于store的增強,將傳入的函數從右到左的執行,避免了層層嵌套,舉個例子:

const x = 10,
    add = x => x + 10,
    sub = x => x - 20,
    sup = x => x * 10;
// 原生方式嵌套實現
add(
    sup(
        sub(
            add(x)
        )
    )
);
// 利用compose改進
const fn = compose(add, sup, sub, add);
fn(x);

對比上面代碼,利用compose會使代碼變得清晰,compose就是函數式編程中的組合:

export default function compose(...funcs) {
    if (funcs.length === 0) {
        return arg => arg;
    }
    if (funcs.length === 1) {
        return funcs[0];
    }        
    return funcs.reduce(
        (a, b) => (
            (...args) => a(b(...args))
        )
    );
};
createStore 什么是store

redux強調的是單一數據源,把所有的state放入到一棵object tree中,這棵樹只能唯一的存在于一個store中,也就是說redux強調整個應用只有一個storestore可以包含

解析依賴函數

該模塊依賴了lodashisPlainObject,該函數用來判斷對象是否繼承了自定義類,實現起來非常簡單:

function isPlainObject(val) {
    // 非對象的情況直接返回false
    if (!isObjectLike(value) || baseGetTag(value) != "[object Object]") {
        return false
      }
      const proto = Object.getPrototypeOf(value)
      // 針對Object.create(null)創建出來的對象
      if (proto === null) {
        return true
      }
      const Ctor = hasOwnProperty.call(proto, "constructor") && proto.constructor
      // prototype.constructor === Object
      return typeof Ctor == "function" && Ctor instanceof Ctor &&
        funcToString.call(Ctor) == objectCtorString
}    
主體函數
// 內部的action,用于reset
export const ActionTypes = {
  INIT: "@@redux/INIT"
};

/*
 * 創建store
 * reducer        reducer函數
 * preloadedState 初始狀態
 * enhancer       增強函數,對createStoren能力進行增強,如devtools
 */
export default function createStore(reducer, preloadedState, enhancer) {
    // 參數修正
    if (typeof preloadedState === "function" && typeof enhancer === "undefined") {
        enhancer = preloadedState;
        preloadedState = undefined;
    }
    if (typeof enhancer !== "undefined") {
        if (typeof enhancer !== "function") {
            throw new Error("Expected the enhancer to be a function.");
        }
        // 返回已經增強后的store
        return enhancer(createStore)(reducer, preloadedState);
    }
    if (typeof reducer !== "function") {
        throw new Error("Expected the reducer to be a function.");
    }
    // 記錄當前值
    let currentReducer = reducer;
    let currentState = preloadedState;
    // 監聽store變化的監聽器(一些回調函數)
    let currentListeners = [];
    let nextListeners = currentListeners;
    // 是否處于dispatch的過程中
    let isDispatching = false;

    /**** 看下面文字解釋 ****/
    function ensureCanMutateNextListeners() {
        if (nextListeners === currentListeners) {
            nextListeners = currentListeners.slice();
        }
    }
    // 給store新增一個監聽器
    function subscribe(listener) {
        if (typeof listener !== "function") {
            throw new Error("Expected listener to be a function.");
        }
        let isSubscribed = true;

        ensureCanMutateNextListeners();
        nextListeners.push(listener);
        // 返回一個卸載方法
        return function unsubscribe() {
            if (!isSubscribed) {
                return
            }
            isSubscribed = false;

            ensureCanMutateNextListeners();
            const index = nextListeners.index(listener);
            nextListeners.splice(index, 1);
        };
    }

    // 返回當前的狀態
    function getState() {
        return currentState;
    }

    function dispatch(action) {
        // 一些類型檢測
        if (!isPlainObject(action)) {
          throw new Error(
            "Actions must be plain objects. " +
            "Use custom middleware for async actions."
          )
        }
        if (typeof action.type === "undefined") {
              throw new Error(
                "Actions may not have an undefined "type" property. " +
                "Have you misspelled a constant?"
              )
        }

        if (isDispatching) {
              throw new Error("Reducers may not dispatch actions.")
        }

        try {
            isDispatching = true;
            // 根據recuder來更新當前狀態
            currentState = currentReducer(currentState, action);
        } finally {
            isDispatching = false;
        }

        const listeners = currentListeners = nextListeners;
        
        // 發布事件
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners;
            listener();
        }
        return action;
    }
    // 更新當前reducer,重置store
    function replaceReducer(nextReducer) {
        if (typeof nextReducer !== "function") {
            throw new Error("Expected the nextReducer to be a function.");
        }

        currentReducer = nextReducer;
        dispatch({ type: ActionTypes.INIT });
    }

    // 初始化store
    dispatch({ type: ActionTypes.INIT });

    // 與Rxjs這種交互,根本看不懂--
    function observable() { ... }
    return {
        getState,
        subscribe,
        dispatch,
        replaceReducer,
        [$$observable]: observable
    };    
};

需要注意的有以下幾點:

為什么需要兩個數組來保存監聽函數

觀察源碼可以發現,currentListenersnextListeners存儲的都是監聽函數,這樣做的目的是保證dispatch的過程不發生錯誤,加入使用一個隊列的話,當執行過程中有監聽函數被移除時,則會發生錯誤,如:當前監聽函數隊列為:[a, b, c],當執行回調函數a后將其移除,則隊列發生改變[b, c],而利用for循環來執行回調,執行到i = 2時會拋出錯誤。

為什么不用forEach

forEachfor差在:

ie8不兼容forEach (ie8 is out)

forEach不能提前終止,但是在dispatch中無此問題

性能,這是forEach最大的問題for要比forEach快的多的多(差不多一倍左右),查看v8代碼也可以感覺出,forEach本質上做的還是for循環,每次loop進行一次判斷和函數調用,自然速度會慢。

applyMiddleware

中間件,expresskoa也就中間件,express中的中間件處理的請求到響應的這一過程redux中的中間件處理的是從action發出到reducer接收到action這一過程,在這個過程中可以利用中間件進行寫日志,處理異步操作等過程,作用就是來增強createStore,給其添加更多的功能。先來看下下面這個簡化的例子:

const calc = (obj) => obj.value + 20;

// 簡單的模擬下stroe
const obj = { calc };

// 加強fn函數
function applyMiddleware(fn, middlewares) {
    middlewares = middlewares.slice();
    middlewares.reverse();
    // 每次改變fn,一次擴展一個功能
    let { calc } = obj;
    middlewares.forEach(
        middleware => calc = middleware(obj)(calc)
    );
    return calc;
}

// arrow function is cool!!!
const logger = obj => next => num => {
    console.log(`num is ${num.value}`);
    let result = next(num);
    console.log(`finish calc, result is ${result}`);
    return result;
};

const check = obj => next => num => {
    console.log(`typeof num.value is ${typeof num.value}`);
    let result = next(num);
    return result;
};

const fn = applyMiddleware(obj, [check, logger]);

fn({ value: 50 });

在上面簡單的例子中為calc做了兩個功能擴展,執行起來就是一個高階函數check->logger->calc,理解了這個再來看看reduxapplyMiddleware的實現:

export default function applyMiddleware(...middlewares) {
    // 利用閉包保存下來了middlewares
    return (createStore) => (reducer, preloadadState, enhancer) => {
        const store = createStore(reducer, preloadadState, enhancer);
        let dispatch = store.dispatch;
        let chain = [];

        // middleware不會改變store,利用閉包保存
        const middlewareAPI = {
            getState: store.getState,
            dispatch: (action) => dispatch(action)
        };

        // chain中的元素仍未函數
        // 接受的參數為`next`    =>     下一個中間件
        chain = middlewares.map(middleware => middleware(middlewareAPI)); 

        // 本身的dispatch放在最后執行
        // dispatch仍未函數,接受的參數為`action`
        // 返回的是一個高階函數,需要注意的是中間件并不會改變原本的action
        // dispatch變成了一個升級版
        dispatch = compose(...chain)(store.dispatch);

        return {
            ...store,
            dispatch
        };                                                                                                                                                                                                                                     
    };
};

附一張圖:

applyMiddleware代碼雖少,但是卻是最難理解的部分

redux-thunk

redux-thunk是一個十分剪短有用的中間件,尤其是在異步應用中,利用redux-thunk可以使action變為一個函數,而不僅僅是一個對象,并且在該函數中仍然可以觸發dispatch

// 讓action可以成為函數
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    // action為函數類型,執行action,dispatch結束
    if (typeof action === "function") {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}
combineReducers

combineReducers用來合并多個reducer

assertReducerSanity來驗證reducer

利用createStore文件中定義的ActionTypes來進行初始化state,也就是定義的reducer會在一開始執行一遍,而后對得到state進行檢測,為undefined拋出異常,同時利用隨機字符串測試,防止其處理type@@redux/INIT而未處理default的情況。

combineReducers

將我們所寫的reducer進行合并,返回一個函數,每次dispatch時,執行函數,遍歷所有的reducer,計算出最終的state

export default function combineReducers(reducers) {
    const reducerKeys = Object.keys(reducers)
    const finalReducers = {}     // 有效reducer集合
    // 驗證reducer,必須是純函數才有效
    for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i]

        if (NODE_ENV !== "production") {
            if (typeof reducers[key] === "undefined") {
                warning(`No reducer provided for key "${key}"`)
            }
        }

        if (typeof reducers[key] === "function") {
            finalReducers[key] = reducers[key]
        }
    }
    const finalReducerKeys = Object.keys(finalReducers)

    let unexpectedKeyCache
    if (NODE_ENV !== "production") {
        unexpectedKeyCache = {}
    }

    let sanityError
    try {
        // 檢測reducer
        assertReducerSanity(finalReducers)
    } catch (e) {
        sanityError = e
    }

    return function combination(state = {}, action) {
        if (sanityError) {
            throw sanityError
        }
        // getUnexpectedStateShapeWarningMessage
        // 檢測state類型是否為0繼承對象
        // 用于找出多余的redcuer并給出警告
        if (NODE_ENV !== "production") {
            const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
            if (warningMessage) {
                warning(warningMessage)
            }
        }

        let hasChanged = false
        const nextState = {}
        // 每次發出一個action會遍歷所有的reducer
        for (let i = 0; i < finalReducerKeys.length; i++) {
            const key = finalReducerKeys[i]
            // 保留之前的state與新生成的state做對比
            const reducer = finalReducers[key]
            const previousStateForKey = state[key]
            const next     StateForKey = reducer(previousStateForKey, action)
            // state為undefined拋出異常
            if (typeof nextStateForKey === "undefined") {
                const errorMessage = getUndefinedStateErrorMessage(key, action)
                throw new Error(errorMessage)
            }
            nextState[key] = nextStateForKey
            // 比較是否數據發生變化
            hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        // 未發生變化返回之前的數據
        return hasChanged ? nextState : state
    }
}
bindActionCreators

這個基本上的作用不大,唯一運用的情況就是將其作為props傳入子組件,對于子組件來說可以全然不知redux的存在。如果利用UI庫的組件來操作頁面狀態,bindActionCreators是一個很好的選擇,實現很簡單:

function bindActionCreator(actionCreator, dispatch) {
    return (...args) => dispatch(actionCreator(...args))
}

bindActionCreators僅僅是遍歷所有的actions返回一個鍵值對。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81465.html

相關文章

  • 深入理解redux

    摘要:深入簡述在快速理解中,我簡單的介紹了的基礎內容,本篇文章中,我們將再度深入。二修改我曾在快速理解中提起,為了解決模塊組件之間需要共享數據和數據可能被任意修改導致不可預料的結果的矛盾,團隊創建了。 深入Redux 簡述 在快速理解redux中,我簡單的介紹了redux的基礎內容,本篇文章中,我們將再度深入redux。 redux解決的問題 數據和函數的層層傳遞 多個組件同時修改某全局變...

    pekonchan 評論0 收藏0
  • redux和react-redux理解和總結(一)

    摘要:使得在變化和異步中可預測。它是數據的唯一來源。指定了應用狀態的變化如何響應并發送到的,只是描述了有事情發生了這一事實,并沒有描述應用如何更新。更新的函數稱為,它是一個純函數,接受舊的和,返回新的。是和之間的橋梁,是把它們聯系到一起的對象。 為什么使用redux 隨著前端單頁面開發越來越復雜,javascript需要管理越來越多的狀態state。如果一個model的變化引起另一個mode...

    skinner 評論0 收藏0
  • 理解 Redux

    摘要:我們知道狀態機是表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型。對照上面我們自己寫的狀態機代碼可以看出的作用告訴狀態樹發生什么變化,及所需要的數據是什么。 前言 我之前開發網站的時候一直用的是 Flux, 自從出了 Redux 之后由于種種原因沒有跟進了解,最近手頭上的事情基本忙的差不多了,抽空閱讀了 Redux 的源碼,并整理了這篇博文。 先說重點: Redux 與 R...

    leejan97 評論0 收藏0
  • Redux之旅-1

    摘要:我們約定,內使用一個字符串類型的字段來表示將要執行的動作。多數情況下,會被定義成字符串常量。要進去工廠加工產品,就得帶上相應得鑰匙,不同的鑰匙對應工廠中上不同的生產線里面的函數,從而有不同的產出改變之后的 時間:2016.4.7-17:24作者:三月懶驢入門配置文章:鏈接 準備 在你的項目下面加入redux / react-redux npm install redux --s...

    hiyang 評論0 收藏0
  • Redux原理分析

    摘要:調用鏈中最后一個會接受真實的的方法作為參數,并借此結束調用鏈。總結我們常用的一般是除了和之外的方法,那個理解明白了,對于以后出現的問題會有很大幫助,本文只是針對最基礎的進行解析,之后有機會繼續解析對他的封裝 前言 雖然一直使用redux+react-redux,但是并沒有真正去講redux最基礎的部分理解透徹,我覺得理解明白redux會對react-redux有一個透徹的理解。 其實,...

    sumory 評論0 收藏0
  • 精讀《重新思考 Redux

    摘要:本周精讀內容是重新思考。數據流對數據緩存,性能優化,開發體驗優化都有進一步施展的空間,擁抱插件生態是一個良好的發展方向。 本周精讀內容是 《重新思考 Redux》。 1 引言 《重新思考 Redux》是 rematch 作者 Shawn McKay 寫的一篇干貨軟文。 dva 之后,有許多基于 redux 的狀態管理框架,但大部分都很局限,甚至是倒退。但直到看到了 rematch,總算...

    IntMain 評論0 收藏0

發表評論

0條評論

piapia

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<