一二三步走,捋清Redux

Risker-C發表於2018-08-18

首先丟擲一個問題。Redux是什麼?

一二三步走,捋清Redux

百度百科給出的解釋是:

Redux對於JavaScript應用而言是一個可預測狀態的容器。換言之,它是一個應用資料流框架,而不是傳統的像underscore.js或者AngularJs那樣的庫或者框架。

Redux官方給出的解釋是

Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。可以讓你構建一致化的應用,執行於不同的環境(客戶端、伺服器、原生應用),並且易於測試。不僅於此,它還提供 超爽的開發體驗,比如有一個時間旅行偵錯程式可以編輯後實時預覽。

其實說的再多,最後還是一句話,就是負責將狀態變得可控。

那麼什麼是狀態呢,在React中State就是用來儲存狀態,而狀態就是一些資料狀態和配置引數。每個元件都可以擁有自己的狀態,而這些變數的值會因為一些操作而改變,而這些改變又會引起其他元件的改變,而state已經不知道什麼時候就脫離了你的控制,而Redux的出現拯救了萬千前端工程師於狀態迷失的水火之中。

阮一峰老師在介紹Redux時提到:

Redux 是一個有用的架構,但不是非用不可。事實上,大多數情況,你可以不用它,只用 React 就夠了。

曾經有人說過這樣一句話。

"如果你不知道是否需要 Redux,那就是不需要它。"

Redux 的創造者 Dan Abramov 又補充了一句。

"只有遇到 React 實在解決不了的問題,你才需要 Redux 。"

雖然說了那麼多但是我們這篇文章的內容呢,是要捋清Redux中的內容,不能跑題啊!

下面開始介紹Redux

1.Redux三大原則

(1).單一資料來源

官方解釋:整個應用的 state 被儲存在一棵 object tree 中,並且這個 object tree 只存在於唯一一個 store 中。 為了避免狀態的混亂,所以在Redux中規定了整個應用的state只存在一棵物件樹中,而這棵樹只能存在一個Store中。對開發者來說,這樣可以更加容易對資料進行除錯,並且可以觀察到資料的詳細變化,在 樹狀結構中,也可以輕鬆實現“撤銷/重做等以前不宜實現的功能

(2).State是隻讀的

官方解釋:唯一改變 state 的方法就是觸發 action,action 是一個用於描述已發生事件的普通物件。 State是不能直接修改的,於React中的state和setState類似,如果需要修改State中的內容,需要先寫一個action物件,通過呼叫這個action來表明你想要State中的內容進行修改的意圖。並且State是不能夠修改的,所以修改的實質是返回一個全新的State。

(3).使用純函式來執行修改

官方解釋:為了描述 action 如何改變 state tree ,你需要編寫 reducers。 Reducers負責根據你給他的action來對State進行操作。Reducers是一個純函式,也就是一個不會產生副作用的函式,因此他最終返回的,是原來的狀態,加上操作的內容產生的新的物件。

2.Redux實現的鋪墊


Redux的實現可以講成一個故事,在一個用玻璃牆圍起來屋子裡面有一個展示牌--State,所有人都可以看見,但是不能夠直接修改展示牌上面的資訊,但是不能修改也不行啊,於是找來了一個專門修改展示牌內容的工匠--reducer,只有他可以修改展示牌上面的State內容,但是State是隻讀的,所以每一次修改都需要工匠重新做一塊牌子,將修改資訊和原來資訊刻在上面,然後展示出來。工匠是住在玻璃牆裡面的,外面的人需要修改展示牌內容,但是沒有辦法進到牆裡面去,所以修改意見沒有辦法傳遞給工匠。於是就產生了一個可以穿過玻璃牆和工匠傳信的信使--action,他可以穿過玻璃牆,傳遞資訊,外面想要修改展示內容的人,只需要將修改意見的暗號--type告訴信使,他便可以告訴工匠,工匠也就按照暗號將資訊修改。故事講完了,下面講講裡面的知識點吧!


(1).展示牌--State:

在Redux第一,二條原則中說到,State儲存在Object tree中,所以在Redux中,所有的State都被儲存在一個單一的物件中,State是隻讀的,所以需要用const來宣告

    //定義State
    const initState={
            todos:[
                {content:"HTML",complete:false},
                {content:"CSS",complete:true},
                {content:"JS",complete:false}
            ],
            visibility:"all"
        }
複製程式碼

(2).信使--action:

action是一個物件,用來表明想要對State進行的操作。因為State被隔離了起來,所以想要操作State怎麼辦呢?只好找了一個信使-action,將想要進行的操作告訴信使,由他把操作傳遞給工匠reducer。action的結構比較簡單,分為下面兩個部分。

a.必需品

信使的作用就是傳信,而這裡的信就是type,所以,每個action必須有type的屬性,並且是唯一的。

        const decrement = {
            type:"DECREMENT"
        }
複製程式碼

b.高階操作--action creators

初級信使只傳遞一個修改的type,而修改的方法是工匠已經規定好的,但是這樣的規定往往不能滿足人們的需求,於是就有了高階信使,他們不再是一個物件,變成了一個方法,他可以接收人們需要增加的其他功能,然後整合成一個初級信使模樣即物件,也就是返回一個物件,而這個物件的功能就比初級的信使要厲害多了。

        function addTodo(text){
            return{
                type:"ADD_TODO",
                text
            }
        }
複製程式碼

(3).工匠--reducer

reducer是一個純函式,接收舊的狀態和action,返回一個新狀態。就行工匠一樣,只需要原本的展示牌的內容和信使傳遞的修改意見,只要他能夠識別暗號,就可以做出一個新的展示牌。

        function reducer(state=initState, action){
            switch(action.type){
                case "INCREMENT":
                    return {count:state.count+action.step}
                case "DECREMENT":
                    return {count:state.count-1}
                default:
                    return state;
            }
        }
複製程式碼

但是有時候State tree過於龐大的時候,每一次操作的過程太複雜,這時候就產生了工匠聯盟。

工匠聯盟

所謂的工匠聯盟是指將原本一個工匠的活,根據State內容分成幾個部分,分別交給不同的工匠(reducer)來完成,每一次操作,工匠們只需要完成自己的部分即可,需要修改的進行修改,不需要修改的,將原本的內容復刻上去,產生一個新的展示牌。

        //定義 reducer
        function todos(state=[],action){
            switch(action.type){
                case "ADD_TODO":
                    return [...state,{content:action.text,complete:false}];
                case "TAGGLE_TODO":
                    return state.map(todo=>{
                        if(todo==action.todo){
                            return Object.assign({},todo,{complete:!todo.complete})
                        }
                        return todo;
                    })
                default:
                    return state;
            }
        }
        // 定義visibility的reducer
        function visibility(state="all",action){
            switch(action.type){
                case "SET_VISIBILITY":
                    return action.filter
                default:
                    return state
            }
        }
        const reducer = Redux.combineReducers({
複製程式碼

3.Redux核心--store

Redux的核心是Store,那麼Store是什麼呢,可以說他就是剛才故事裡的那個玻璃屋的管理者,他有三個能力,一個是得到展示欄的內容,一個是訂閱展示牌改變,一個是派發改變展示欄資訊的功能

(1)獲取狀態

雖然我們說是把Store比作了玻璃屋,但是在程式碼世界裡面,沒有所謂的視聽說,所以要想獲得展示牌的內容,就需要使用store提供的第一個能力--store.getState()。通過使用這個方法,就可以拿到展示牌的內容了。

        //取值
        console.log(store.getState());
複製程式碼

(2)訂閱資訊

雖然使用第一個方法可以拿到展示牌的內容,但是拿到了的資料不會因為State的改變而改變,所以當其他人改變了展示牌上面的State,就需要重新獲取,這無疑是不靠譜的方法,所以這個時候就需要使用Store的第二個能力--store.subscibe()來設定監聽,一旦state發生變化,立即可以執行這個監聽方法內部的函式。

        //訂閱
        store.subscribe(()=>{
            console.log(store.getState());
        })
複製程式碼

(3)派發任務

既然能夠獲取資料了,自然是可以改變的,信使進入玻璃牆就是使用的Store的第三個能力--store.dispatch(),在這個方法裡,至少需要傳遞一個引數-action,就好比使用了這個方法,就在玻璃牆上面開啟了一個通道,此時信使就可以通過這個通道,進入到了裡面。

        // 通過dispatch派發一個action
        store.dispatch(addTodo("redux"));
複製程式碼

通過三步的介紹,相信你已經初步瞭解了Redux的內容,接下來在玻璃牆這裡還有許許多多的內容等待著我們,一步一個腳印的走,我們也一定能夠穿過屬於你的玻璃牆的,讓我們一同加油

相關文章