<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國際加速解決方案。 廣告
                &emsp;&emsp;Redux是一個可預測的狀態容器,不但融合了函數式編程思想,還嚴格遵循了單向數據流的理念。Redux繼承了Flux的架構思想,并在此基礎上進行了精簡、優化和擴展,力求用最少的API完成最主要的功能,它的核心代碼短小而精悍,壓縮后只有幾KB。Redux約定了一系列的規范,并且標準化了狀態(即數據)的更新步驟,從而讓不斷變化、快速增長的大型前端應用中的狀態有跡可循,既利于問題的重現,也便于新需求的整合。注意,Redux是一個獨立的庫,可與React、Ember或jQuery等其它庫搭配使用。 &emsp;&emsp;在Redux中,狀態是不能直接被修改的,而是通過Action、Reducer和Store三部分協作完成的。具體的運作流程可簡單的概括為三步,首先由Action說明要執行的動作,然后讓Reducer設計狀態的運算邏輯,最后通過Store將Action和Reducer關聯并觸發狀態的更新,下面用代碼演示這個流程。 ~~~js function caculate(previousState = {digit: 0}, action) { //Reducer let state = Object.assign({}, previousState); switch (action.type) { case "ADD": state.digit += 1; break; case "MINUS": state.digit -= 1; } return state; } let store = createStore(caculate); //Store let action = { type: "ADD" }; //Action store.dispatch(action);   //觸發更新 store.getState();   //讀取狀態 ~~~ &emsp;&emsp;通過上面的代碼可知,Action是一個普通的JavaScript對象,Reducer是一個純函數,Store是一個通過createStore()函數得到的對象,如果要觸發狀態的更新,那么需要調用它的dispatch()方法。先對Redux有個初步的感性認識,然后在接下來的章節中,將圍繞這段代碼展開具體的分析。 ## 一、三大原則 &emsp;&emsp;只有遵守Redux所設計的三大原則,才能讓狀態變得可預測。 &emsp;&emsp;(1)單一數據源(Single source of truth)。 &emsp;&emsp;前端應用中的所有狀態會組成一個樹形的JavaScript對象,被保存到一個Store中。這樣不但能避免數據冗余,還易于調試,并且便于監控任意時刻的狀態,從而減少出錯概率。不僅如此,過去難以達成的功能(例如即時保存、撤銷重做等),現在實現起來也變得易如反掌了。在應用的任意位置,可通過Store的getState()方法讀取到當前的狀態。 &emsp;&emsp;(2)保持狀態只讀(State is read-only)。 &emsp;&emsp;若要改變Redux中的狀態,得先派發一個Action對象,然后再由Reducer函數創建一個新的狀態對象返回給Redux,以此保證狀態的只讀,從而讓狀態管理能夠井然有序的進行。 &emsp;&emsp;(3)狀態的改變由純函數完成(Changes are made with pure functions)。 &emsp;&emsp;這里所說的純函數是指Reducer,它沒有副作用(即輸出可預測),其功能就是接收Action并處理狀態的變更,通過Reducer函數使得歷史狀態變得可追蹤。 ## 二、主要組成 &emsp;&emsp;Redux主要由三部分組成:Action、Reducer和Store,本節將會對它們依次進行講解。 **1)Action** &emsp;&emsp;由開發者定義的Action本質上就是一個普通的JavaScript對象,Redux約定該對象必須包含一個字符串類型的type屬性,其值是一個常量,用來描述動作意圖。Action的結構可自定義,盡量包含與狀態變更有關的信息,以下面遞增數值的Action對象為例,除了必需的type屬性之外,還額外附帶了一個表示增量的step屬性。 ~~~js { type: "ADD", step: 1 } ~~~ &emsp;&emsp;如果項目規模越來越大,那么可以考慮為Action加個唯一號標識或者分散到不同的文件中。 &emsp;&emsp;通常會用Action創建函數(Action Creator)生成Action對象(即返回一個Action對象),因為函數有更好的可控性、移植性和可測試性,下面是一個簡易的Action創建函數。 ~~~js function add() { return { type: "ADD", step: 1 }; } ~~~ **2)Reducer** &emsp;&emsp;Reducer函數對狀態只計算不存儲,開發者可根據當前業務對其進行自定義。此函數能接收2個參數:previousState和action,前者表示上一個狀態(即當前應用的狀態),后者是一個被派發的Action對象,函數體中的返回值是根據這兩個參數生成的一個處理過的新狀態。 &emsp;&emsp;Redux在首次執行時,由于初始狀態為undefined,因此可以為previousState設置初始值,例如像下面這樣使用ES6默認參數的語法。 ~~~js function caculate(previousState = {digit: 0}, action) { let state = Object.assign({}, previousState); //省略更新邏輯 return state; } ~~~ &emsp;&emsp;在編寫Reducer函數時,有三點需要注意: &emsp;&emsp;(1)遵守純函數的規范,例如不修改參數、不執行有副作用的函數等。 &emsp;&emsp;(2)在函數中可以先用Object.assign()創建一個狀態對象的副本,隨后就只修改這個新對象,注意,方法的第一個參數要像上面這樣傳一個空對象。 &emsp;&emsp;(3)在發生異常情況(例如無法識別傳入的Action對象),返回原來的狀態。 &emsp;&emsp;當業務變得復雜時,Reducer函數中處理狀態的邏輯也會隨之變得異常龐大。此時,就可以采用分而治之的設計思想,將其拆分成一個個小型的獨立子函數,而這些Reducer函數各自只負責維護一部分狀態。如果需要將它們合并成一個完整的Reducer函數,那么可以使用Redux提供的combineReducers()函數。該函數會接收一個由拆分的Reducer函數組成的對象,并且能將它們的結果合并成一個完整的狀態對象。下面是一個用法示例,先將之前的caculate()函數拆分成add()和minus()兩個函數,再作為參數傳給combineReducers()函數。 ~~~js function add(previousState, action) { let state = Object.assign({}, previousState); state.digit = "digit" in state ? (state.digit + 1) : 0; return state; } function minus(previousState, action) { let state = Object.assign({}, previousState); state.number = "number" in state ? (state.number - 1) : 0; return state; } let reducers = combineReducers({add, minus}); ~~~ &emsp;&emsp;combineReducers()會先執行一次這兩個函數,也就是說reducers()函數所要計算的初始狀態不再是undefined,而是下面這個對象。注意,{add, minus}用到了ES6新增的簡潔屬性語法。 ~~~js { add: { digit: 0 }, minus: { number: 0 } } ~~~ **3)Store** &emsp;&emsp;Store為Action和Reducer架起了一座溝通的橋梁,它是Redux中的一個對象,發揮了容器的作用,保存著應用的狀態,包含4個方法: &emsp;&emsp;(1)getState():獲取當前狀態。 &emsp;&emsp;(2)dispatch(action):派發一個Action對象,引起狀態的修改。 &emsp;&emsp;(3)subscribe(listener):注冊狀態更新的監聽器,其返回值可以注銷該監聽器。 &emsp;&emsp;(4)replaceReducer(nextReducer):更新Store中的Reducer函數,在實現Redux熱加載時可能會用到。 &emsp;&emsp;在Redux應用中,只會包含一個Store,由createStore()函數創建,它的第一個參數是Reducer()函數,第二個參數是可選的初始狀態,如下代碼所示,為其傳入了開篇的caculate()函數和一個包含digit屬性的對象。 ~~~js let store = createStore(caculate, {digit: 1}); ~~~ &emsp;&emsp;caculate()函數會增加或減少狀態對象的digit屬性,其中增量或減量都是1。接下來為Store注冊一個監聽器(如下代碼所示),當狀態更新時,就會打印出最新的狀態;而在注銷監聽器(即調用unsubscribe()函數)后,控制臺就不會再有任何輸出。 ~~~js let unsubscribe = store.subscribe(() => //注冊監聽器 console.log(store.getState()) ); store.dispatch({ type: "ADD" }); //{digit: 2} store.dispatch({ type: "ADD" }); //{digit: 3} unsubscribe();       //注銷監聽器 store.dispatch({ type: "MINUS" });  //沒有輸出 ~~~ ## 三、綁定React &emsp;&emsp;雖然Redux和React可以單獨使用(即沒有直接關聯),但是將兩者搭配起來能發揮更大的作用。React應用的規模一旦上去,那么對狀態的維護就變得愈加棘手,而在引入Redux后就能規范狀態的變化,從而扭轉這種窘境。Redux官方提供了一個用于綁定React的庫:react-redux,它包含一個connect()函數和一個Provider組件,能很方便的將Redux的特性融合到React組件中。 **1)容器組件和展示組件** &emsp;&emsp;由于react-redux庫是基于容器組件和展示組件相分離的開發思想而設計的,因此在正式講解react-redux之前,需要先理清這兩類組件的概念。 &emsp;&emsp;容器組件(Container Component),也叫智能組件(Smart Component),由react-redux庫生成,負責應用邏輯和源數據的處理,為展示組件傳遞必要的props,可與Redux配合使用,不僅能監聽Redux的狀態變化,還能向Redux派發Action。 &emsp;&emsp;展示組件(Presentational Component),也叫木偶組件(Dumb Component),由開發者定義,負責渲染界面,接收從容器組件傳來的props,可通過props中的回調函數同步源數據的變更。 &emsp;&emsp;容器組件和展示組件是根據職責劃分的,兩者可互相嵌套,并且它們內部都可以包含或省略狀態,一般容器組件是一個有狀態的類,而展示組件是一個無狀態的函數。 **2)connect()** &emsp;&emsp;react-redux提供了一個柯里化函數:connect(),它包含4個可選的參數(如下代碼所示),用于連接React組件與Redux的Store(即讓展示組件關聯Redux),生成一個容器組件。 ~~~js connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) ~~~ &emsp;&emsp;在使用connect()時會有兩次函數執行,如下代碼所示,第一次是獲取要使用的保存在Store中的狀態,connect()函數的返回結果是一個函數;第二次是把一個展示組件Dumb傳到剛剛返回的函數中,繼而將該組件裝飾成一個容器組件Smart。 ~~~js const Smart = connect()(Dumb); ~~~ &emsp;&emsp;接下來會著重講解函數的前兩個參數:mapStateToProps和mapDispatchToProps,另外兩個參數(mergeProps和options)可以參考官方文檔的說明。 **3)mapStateToProps** &emsp;&emsp;這是一個包含2個參數的函數(如下代碼所示),其作用是從Redux的Store中提取出所需的狀態并計算成展示組件的props。如果connect()函數省略這個參數,那么展示組件將無法監聽Store的變化。 ~~~js mapStateToProps(state, [ownProps]) ~~~ &emsp;&emsp;第一個state參數是Store中保存的狀態,第二個可選的ownProps參數是傳遞給容器組件的props對象。在一般情況下,mapStateToProps()函數會返回一個對象,但當需要控制渲染性能時,可以返回一個函數。下面是一個簡單的例子,還是沿用開篇的caculate()函數,Provider組件的功能將在后文中講解。 ~~~js let store = createStore(caculate); function Btn(props) {   //展示組件 return <button>{props.txt}</button>; } function mapStateToProps(state, ownProps) { console.log(state); //{digit: 0} console.log(ownProps); //{txt: "提交"} return state; } let Smart = connect(mapStateToProps)(Btn); //生成容器組件 ReactDOM.render( <Provider store={store}> <Smart txt="提交" /> </Provider>, document.getElementById("container") ); ~~~ &emsp;&emsp;Btn是一個無狀態的展示組件,Store中保存的初始狀態不是undefined,容器組件Smart接收到了一個txt屬性,在mapStateToProps()函數中打印出了兩個參數的值。 &emsp;&emsp;當Store中的狀態發生變化或組件接收到新的props時,mapStateToProps()函數就會被自動調用。 **4)mapDispatchToProps** &emsp;&emsp;它既可以是一個對象,也可以是一個函數,如下代碼所示。其作用是綁定Action創建函數與Store實例所提供的dispatch()方法,再將綁好的方法映射到展示組件的props中。 ~~~js function add() { //Action創建函數 return {type: "ADD"}; } var mapDispatchToProps = { add };      //對象 var mapDispatchToProps = (dispatch, ownProps) => { //函數 return {add: bindActionCreators(add, dispatch)}; } ~~~ &emsp;&emsp;當mapDispatchToProps是一個對象時,其包含的方法會作為Action創建函數,自動傳遞給Redux內置的bindActionCreators()方法,生成的新方法會合并到props中,屬性名沿用之前的方法名。 &emsp;&emsp;當mapDispatchToProps是一個函數時,會包含2個參數,第一個dispatch參數就是Store實例的dispatch()方法;第二個ownProps參數的含義與mapStateToProps中的相同,并且也是可選的。函數的返回值是一個由方法組成的對象(會合并到props中),在方法中會派發一個Action對象,而利用bindActionCreators()方法就能簡化派發流程,其源碼如下所示。 ~~~js function bindActionCreator(actionCreator, dispatch) { return function () { return dispatch(actionCreator.apply(this, arguments)); }; } ~~~ &emsp;&emsp;展示組件能通過讀取props的屬性來調用傳遞過來的方法,例如在Btn組件的點擊事件中執行props.add(),觸發狀態的更新,如下所示。 ~~~js function Btn(props) { return <button onClick={props.add}>{props.txt}</button>; } ~~~ &emsp;&emsp;通過上面的分析可知,mapStateToProps負責展示組件的輸入,即將所需的應用狀態映射到props中;mapDispatchToProps負責展示組件的輸出,即將需要執行的更新操作映射到props中。 **5)Provider** &emsp;&emsp;react-redux提供了Provider組件,它能將Store保存在自己的Context(在[第9篇](https://www.cnblogs.com/strick/p/10668965.html)做過講解)中。如果要正確使用容器組件,那么得讓其成為Provider組件的后代,并且只有這樣才能接收到傳遞過來的Store。Provider組件常見的用法如下所示。 ~~~html <Provider store={store}> <Smart /> </Provider> ~~~ &emsp;&emsp;Provider組件位于頂層的位置,它會接收一個store屬性,屬性值就是createStore()函數的返回值,Smart是一個容器組件,被嵌套在Provider組件中。 ***** > 原文出處: [博客園-React躬行記](https://www.cnblogs.com/strick/category/1455720.html) [知乎專欄-React躬行記](https://zhuanlan.zhihu.com/pwreact) 已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
                  <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>

                              哎呀哎呀视频在线观看