從 0 到 1 理解 React redux 的設計思想 (5步分解, 保證小白都能看得懂)

liyuanzhe-cn發表於2019-05-08

把之前學習redux的手寫學習筆記分享出來一下,方便大家理解redux思想,畢竟前端工程師裡面都說,

初級前端和中級前端的區別就是是否懂設計模式和麵向物件

這個是將redux思想的一個拆分, 將 redux 拆分成 5 部分,最終拼成一個react redux,

為什麼使用react redux ?

有了redux之後 state不再是誰都可以任意呼叫setState修改的資料了,

react沒有redux 和 有redux的核心區別**

react: 通過 setState修改state資料,再執行渲染;

react-redux: 通過 dispatch來判斷是否執行setState,dispatch檢測通過,執行setState函式, 否則不予執行;


1. 引入dispatch管理對setState的呼叫


    <div id="title"></div>
    <div id="contents"></div>

    <script>
        
        // 渲染模組
        function render() {
            document.getElementById('title').innerHTML = state.title;
            document.getElementById('contents').innerHTML = state.content;
        }

        //資料模組
        var state = {
            title: '新的標題',
            content: '新的內容'
        }

        //初次渲染執行
        render();

        //更改資料模組 ** 更改後觸發資料渲染
        function setState(newState) {
            this.state = {
                ...state,
                ...newState
            }
            render()
        }

    </script>
複製程式碼

下面這部分是redux思想的和體現方式, 通過dispath判斷引數的type是否合法, 合法才可以可以呼叫setState

<script>

        // 管理模組, 想要觸發資料改變請執行這個函式, 並且要給指定的type, 否則不執行setState
        var dispatch = function (action) {
            switch (action.type) {
                case 'CHANGE_TITLE': // 傳過來的type正確才能setState
                    setState({
                        title: action.newTitle
                    })
                    break;
                default:
                    break;
            }
        }
        //修改資料呼叫dispatch函式, 只有裡面的json的type經過了dispatch檢測才能執行相應的setState
        dispatch(
            {
                type: 'CHANGE_TITLE',
                newTitle: '我是經過dispatch函式允許修改後的新標題'
            }
        )
      
    </script>  
複製程式碼

2. 引入subscriber

<div id="title"></div>
    <div id="contents"></div>
    <script>
        function render() {
            document.getElementById('title').innerHTML = state.title;
            document.getElementById('contents').innerHTML = state.content;
        }
 
        var state = {
            title: '新的標題',
            content: '新的內容'
        }

        render()
   
複製程式碼

建立陣列listeners, 引入訂閱subscriber 函式,該函式向陣列中訂閱(push)新的事件,比如render渲染函式,在成功觸發setState後,會對listensers陣列裡面的函式依次執行。


        var dispatch = function (action) {
            switch (action.type) {
                case 'CHANGE_TITLE': 
                    state = {
                        ...state,
                        title:action.newTitle
                    }
                    break;
                default:
                    break;
            }
            listeners.forEach(e=>e()) //依次執行陣列中訂閱的事件
        }

        var listeners = []; //這個陣列放setState之後執行的事件, 

        var subscribe = function(listener){ //用subscriber函式把事件push到事件陣列中
            listeners.push(listener)
        }

        subscribe(render) // 陣列中放入render函式

        dispatch(
            {
                type: 'CHANGE_TITLE',
                newTitle: '我是經過dispatch函式允許修改後的新標題'
            }
        )
    </script>
</body>
複製程式碼

3. 初步封裝 createStore

    div id="title"></div>
    <div id="contents"></div>
    <script>
        //渲染函式
        function render(state) {
            document.getElementById('title').innerHTML = state.title;
            document.getElementById('contents').innerHTML = state.content;
        }

        //store 核心部分
        var createStore = function () {
            //state資料
            var state = {
                title: '這是一個標題',
                content: '這是一段內容'
            }
            
            //執行函式倉庫
            var listeners = [];
            
            //獲取state資料
            var getState = function () {
                return state;
            }
            
            //dispatch監控 type是否合法,合法才觸發setState函式
            var dispatch = function (action) {
                switch (action.type) {
                    case 'CHANGE_TITLE':
                        state = {
                            ...state,
                            title: action.newTitle
                        }
                        break;
                    default:
                        break;
                }
                listeners.forEach(e => e())
            }
            
            //事件訂閱函式
            var subscribe = function (listener) {
                listeners.push(listener)
            }
            
            // 暴露呼叫介面
            return {
                dispatch,
                subscribe,
                getState
            }

        }

        //呼叫部分
        //建立例項化物件
        var store = createStore();
        
        //解構獲取三個介面函式
        var { subscribe, dispatch, getState } = store;
        
        //訂閱事件
        subscribe(() => render(getState()));
        
        //請求dispatch改變狀態
        dispatch(
            {
                type: 'CHANGE_TITLE',
                newTitle: '我是經過dispatch函式允許修改後的新標題'
            }
        )
        render(getState())
    </script>
複製程式碼

但是這個createStore函式存在不純的問題,含有定好的state 和 dispatch,接下來就是對該函式進行提純處理。


4. createStore函式提純處理,讓createStore 和 state,setState相分離 , 將state和setState放入appReducer函式中

    <div id="title"></div>
    <div id="contents"></div>
    <script>
    
        //store 核心部分
        var createStore = function () {
            // 將state設定為 null;
            var state = null
            
            var listeners = [];
            
            var dispatch = function (action) {
                //呼叫dispatch時, 執行appReducer做判斷
                state = appReducer(state, action);
                listeners.forEach(e => e());
            }
            
            //呼叫dispatch初始化state,獲取appReducer中的預設state。
            dispatch({}) 
            
            var subscribe = function (listener) {
                listeners.push(listener)
            }
            
            var getState = function () {
                return state;
            }
            
            //暴露介面
            return {
                dispatch,
                subscribe,
                getState
            }
        }
        
        var appReducer = function (state, action) {
            //初始化store中的state
            //因為state初始值為null
            if (!state) {
                return {
                    title: '這是一個標題',
                    content: '這是一段內容'
                }
            }
            
            //更新state
            switch (action.type) {
                case 'CHANGE_TITLE':
                    return {
                        ...state,
                        title: action.newTitle
                    }
                    break;
                default:
                    return state;
            }
        }
        
        var store = createStore();

        var { subscribe, dispatch, getState } = store;
        
        subscribe(() => render(getState()))
        
        dispatch(
            {
                type: 'CHANGE_TITLE',
                newTitle: '我是經過dispatch函式允許修改後的新標題'
            }
        )

        function render(state) {
            document.getElementById('title').innerHTML = state.title;
            document.getElementById('contents').innerHTML = state.content;
        }

        //呼叫部分
        render(getState())


    </script>
複製程式碼

此時 createStore依然不是一個純函式, 依然無法獨立, 因為裡面有寫死的appReducer函式的執行;


5. 徹底讓createStore變成純建構函式 , appReducer作為引數傳入到createStore。

        // 現在已經是非常乾淨的純建構函式了
        function createStore(appReducer) {
            state = null;
            var listeners = [];
            function dispatch(action) {
                state = appReducer(state, action)
                listeners.map(e => e())
            }
            dispatch({})
            function getState() {
                return state
            }
            function subscribe(listener) {
                listeners.push(listener);
            }
            return {
                dispatch,
                getState,
                subscribe
            }
        }
        
        // appReucer 函式
        function appReducer(state, action) {
            //初始化資料
            if (!state) {
                return {
                    title: '你好',
                    content: '歡迎光臨'
                }
            }
            
            switch (action.type) {
                case 'CHANGE_TITLE':
                    return {
                        ...state,
                        title: action.newTitle
                    }
                    break;
                default:
                    break;
            }
        }
        
        //使用createStore部分
        var store = createStore(appReducer);

        var { dispatch,
            getState,
            subscribe } = store;

        subscribe(() => render(getState()))
        
        dispatch(
            {
                type: "CHANGE_TITLE",
                newTitle: '我是經過dispatch函式允許修改後的新標題'
            }
        )

        function render(state) {
            document.getElementById('title').innerHTML = state.title;
            document.getElementById('content').innerHTML = state.content;
        }

        render(getState());
複製程式碼

至此,react redux 核心思想已經搞定了,相信你一定看得懂。

相關文章