<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                *本文為公司前端團隊內部分享的文案,是在網上剽竊、參考、學習了諸多文章和代碼后,加上自己的理解而成,如果對你有所幫助,不生榮幸。 最終代碼在github,地址:[https://github.com/fujiazhang/Redux](https://github.com/fujiazhang/Redux)* 正文: 因為一開始我是做vue技術棧,剛接觸react的時候,對于redux有很多不理解的地方,因為vuex封裝的很好,而react-redux就很簡陋,對于redux也有很多不理解的地方,但是照著文檔寫也ok,但是總歸理解不深入,借著這次分享的機會,參考很多優秀的文章代碼,總算是搞懂了redux, 當然本次分享是是redux,不是react-redux,。 首先, redux是一種架構,他和react沒有任何關系,可以用在任何東西,像是什么 connect之類是屬于react-redux,ok, 現在請忘掉reducer、store、dispatch、middleware這些單詞,我們一步步來推導。 ## 一、redux的本質就是:就是使用store來管理state的數據管理器 我們首先定義一個狀態管理器: ``` let state = { name: 'zhangsan' } ``` ok, 接下來我們來修改和使用它 ``` console.log(state.name) ``` now, 我們現在有了一個狀態管理器了,現在一步步來完善這個狀態管理器。 ok,我們現在面臨第一個問題,我們沒辦法在修改的時候,知道我們的狀態被修改了,比如我頁面上有地方引用了這個數據,但是被修改了,卻不知道(無法更新同步view),這里使用訂閱/發布模式來解決這個修改了數據需要被通知(知道被修改了)的這個問題。 ``` let state = { name: 'zhangsan' } //保存訂閱者數據集合 const liesteners = [] //訂閱 function subscribe(liestener) { liesteners.push(liestener) } function changeState(newState) { state = newState //發布 liesteners.forEach(f = >f()) } ``` ok,代碼如上,我們來使用下 ``` subscribe(() = >{ console.log('state is changed', state) }) //更改狀態 changeState({ name: 'lisi' }) ``` 現在我們可以看到,我們修改 name 的時候,會輸出相應的 state值, 解決了當數據更改時,無法知道修改(或者說收到通知)這個問題,現在我們有新的問題: * 這個狀態管理器只能管理我這一個對象,不通用 * 公共的代碼要封裝起來 我們來抽象一下: ``` function createStore(initSate) { let state = initSate const liesteners = [] //訂閱集合 function changeState(newState) { state = newState /*發布*/ liesteners.forEach(f = >f()) } /*訂閱*/ function subscribe(f) { liesteners.push(f) } function getStore() { return state } return { getStore, changeState, subscribe } } ``` ok, 我們來試試: ``` store.subscribe(()=> { console.log('state is changed:', store.getStore()) }) store.changeState({ name: 'fujiazhang' }) store.changeState({ name: 'guolei' }) store.changeState({ name: 'yuanying' }) ``` 輸入如下: ![](images/screenshot_1596460285185.png) 嗯,不錯,我們來試試來使用這個狀態管理器管理多個狀態 ``` const store = createStore(initSate) store.subscribe(() = >{ console.log('state is changed:', store.getStore()) }) store.changeState({...store.getStore(), no1: 'zhangsan' }) store.changeState({...store.getStore(), no2: 'lisi' }) store.changeState({...store.getStore(), no3: 'wangwu' }) ``` 運行輸出結果如下: ![](images/screenshot_1596460536321.png) 嗯,很爽,一切如我們想象的一致。 但是,但是,我們發現有一個嚴重的問題,我的傳入修改的對象是任何值,隨意傳,想傳啥,這肯定是不是我們所期望的,我們期望的肯定是,有固定的值,只允許,我們的nox 為傳入的值,我們可以這樣來解決: 1. 制定一個 state 修改計劃,告訴 store,我的修改計劃是什么。 2. 修改 store.changeState 方法,告訴它修改 state 的時候,按照我們的計劃修改。 我們來設置一個 plan 函數,接收現在的 state,和一個 action,返回經過改變后的新的 state。 ``` function plan(state, action) { switch (action.type) { case 'CHANGE_NO_1': return {...state, no1: action.data } break; default: return state break; } } ``` 我們把這個計劃告訴 store,store.changeState 以后改變 state 要按照我的計劃來改。 現在的整體代碼如下: ``` function createStore(initSate) { let state = initSate const liesteners = [] function changeState(action) { state = plan(state, action) liesteners.forEach(f = >f()) } function subscribe(f) { liesteners.push(f) } function getStore() { return state } return { getStore, changeState, subscribe } } function plan(state, action) { switch (action.type) { case 'CHANGE_NO_1': return {...state, no1: action.data } break; default: return state break; } } const initSate = { no1: '', no2: '', no3: '' } const store = createStore(initSate) store.subscribe(() = >{ console.log('state is changed:', store.getStore()) }) store.changeState({ type: 'CHANGE_NO_1', data: 'zhangsan' }) ``` 我們來運行一波,結果如下: ![](images/screenshot_1596511272746.png) ok, 結果很理想,接下來我們把名字替換一下,到這里為止,我們已經實現了一個有計劃的狀態管理器!現在呢給 plan 和 changeState 改下名字好不好? plan 改成 reducer,changeState 改成 dispatch! ,嗯,和redux一致了。 現在的代碼如下: ``` function createStore(initSate) { let state = initSate const liesteners = [] function dispatch(action) { state = reducer(state, action) liesteners.forEach(f = >f()) } function subscribe(f) { liesteners.push(f) } function getStore() { return state } return { getStore, dispatch, subscribe } } function reducer(state, action) { switch (action.type) { case 'CHANGE_NO_1': return {...state, no1: action.data } break; default: return state break; } } const initSate = { no1: '', no2: '', no3: '' } const store = createStore(reducer, initSate) store.subscribe(() = >{ console.log('state is changed:', store.getStore()) }) store.dispatch({ type: 'CHANGE_NO_1', data: 'zhangsan' }) ``` ok, 到了這里,我們先把代碼分模塊拆開,現在一股腦的在一個index.js文件里,看著也累。組件化拆分后目錄如下: ![](images/screenshot_1596512459047.png) 我們繼續,到這里,其實已經有問題了,因為我們不可能把所有的計劃函數( reducer)寫在一個文件里,我們肯定是期望一個組建一個reducer, 比如支付組件一個reducer, 登陸組件一個reducer,隨著業務的累計,肯定會有大大大大量的reducer 所以,我們需要按組件來拆分出很多個 reducer 函數,然后通過一個函數來把他們合并起來。 現在我們來模擬修改一個state里的 兩個數據。 reducer1: ``` export function no1Reducer(state, action) { switch (action.type) { case 'CHANGE_NO_1': return {...state, no1: action.data } break; default: return state break; } } ``` reducer2 ``` export function no2Reducer(state, action) { switch (action.type) { case 'CHANGE_NO_2': return {...state, no2: action.data } break; default: return state break; } } ``` ok, 我們現在來實現一個combineReducer函數,大概這樣用 ~~~ const reducer = combineReducers({ counter: counterReducer, info: InfoReducer }); ~~~ 我們來實現這個combineReducer函數: ``` export function combineReducer(reducers) { const reducersKey = Object.keys(reducers) return (state = {}, action) = >{ const newState = {} reducersKey.forEach(key = >{ let reducer = reducers[key] newState[key] = reducer(state[key], action) }) return newState } } ``` 來試試調用: ![](images/screenshot_1596515969322.png) 嗯,完美的實現了合并reducer, ![](images/screenshot_1596515989556.png) 我們把 reducer 按組件維度拆分了,通過 combineReducers 合并了起來。但是還有個問題, state 我們還是寫在一起的,這樣會造成 state 樹很龐大,不直觀,很難維護。我們需要拆分,一個 state,一個 reducer 寫一塊。 ![](images/screenshot_1596516570363.png) 我們修改下 createStore 函數,增加一行`dispatch({ type: "" }) ![](images/screenshot_1596516767177.png) 這里為什么這樣做就能ok: 1. createStore 的時候,用一個不匹配任何 type 的 action,來觸發`state = reducer(state, action)` 2. 因為 action.type 不匹配,每個子 reducer 都會進到 default 項,返回自己初始化的 state,這樣就獲得了初始化的 state 樹了。 目前為止,我們的redux已經實現的差不多了。 ### 中間件 middleware 中間件 middleware 是 redux 中比較難理解的地方 ,**中間件的本質是對 dispatch 的擴展,或者說重寫,增強 dispatch 的功能!** 現在我們需有一個需求,就是想要在每次修改state的時候,把日志輸出到控制臺,包括修改的action, 修改前后的值(和taro做小程序里,里差不多的需求) 看圖 ![](images/screenshot_1596522279576.png)![](images/screenshot_1596522289876.png) ``` import { createStore, combineReducer } from "./redux"; import { no1Reducer } from "./reducer/no1"; import { no2Reducer } from "./reducer/no2"; import { asyncHanlde } from "./middleWares/asyncHanlde"; import { logger } from "./middleWares/logger"; import { timesmap } from "./middleWares/timesmap"; const reducer = combineReducer({ no1: no1Reducer, no2: no2Reducer }) const store = createStore(reducer) const next = store.dispatch const time = timesmap(store) const asyncH = asyncHanlde(store) const log = logger(store) store.dispatch = time(asyncH(log((next)))) store.subscribe(() => { console.log('state is changed:', store.getStore()) }) store.dispatch({ type: 'CHANGE_NO_1', data: 'zhangsan' }) store.dispatch({ type: 'CHANGE_NO_2', data: 'lisi' }) ``` 其實到這里,就算ok了,你會發現和redux核心源碼已經90%相似了,還有一些函數,如applyMiddleware(對中間件的用法優化),還有如compoose函數,(將中間件的使用如 [a,b,c] 轉換成 a(b(c)))找各種形式,沒有實現,但是這個沒必要在深入,只是一些語法糖,還有一些函數參數驗證我們的reducer只能吃純函數、訂閱時間的退訂這些細枝末節的沒有實現,但是我們抓住主線就ok了。 ### 總結 到了最后,我想把 redux 中關鍵的名詞列出來,你每個都知道是干啥的嗎? * createStore 創建 store 對象,包含 getState, dispatch, subscribe, replaceReducer * reducer reducer 是一個計劃函數,接收舊的 state 和 action,生成新的 state * action action 是一個對象,必須包含 type 字段 * dispatch `dispatch( action )`觸發 action,生成新的 state * subscribe 實現訂閱功能,每次觸發 dispatch 的時候,會執行訂閱函數 * combineReducers 多 reducer 合并成一個 reducer * middleware 擴展 dispatch 函數! 你再看 redux 流程圖,是不是大徹大悟了? ![](https://img.kancloud.cn/c3/ad/c3adb8f9e5e1582daea1865ecc83bdc0_500x375.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看