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

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

初級前端和中級前端的區別就是是否懂設計模式和麪向對象

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

爲何使用react redux ?

有了redux以後 state再也不是誰均可以任意調用setState修改的數據了,json

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 核心思想已經搞定了,相信你必定看得懂。


把本身寫的createStore 應用在react中

store的三個接口:
dispatch, 修改store裏面的state
subscribe, 訂閱渲染組件的事件 this.setState
getState, 獲取store裏面的state

這樣, 組件就無需維護本身的state 而使用外部引入的store裏面的stateredux

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';

import createStore from './createStore';

let appReducer = (state, action) => {
    if (!state) {
        return {
            title: "這個是標題",
            content: "這個是內容"
        }
    }
    switch (action.type) {
        case "CHANGE_TITLE":
            return {
                ...state,
                title: action.newTitle
            }
        case "CHANGE_CONTENT":
            return {
                ...state,
                content: action.newContent
            }
        default:
            return state;
    }
}

var store = createStore(appReducer)

//組件將不用去維護本身的state
class App extends Component {
    constructor() {
        super();
        //訂閱觸發渲染的事件 this.setState
        store.subscribe(() => {
            this.setState(store.getState)
        })
    }
    _chengeTitle(newTitle) {
        //調用dispatch去修改store中的state, 隨後dispatch會 按順序執行listeners數組中訂閱的事件
        store.dispatch({
            type: "CHANGE_TITLE",
            newTitle: newTitle
        })
    }
    render() {
        const { title, content } = store.getState();
        { console.info(store.getState()) }
        return (
            < div >
                <h1>{title}</h1>
                <p>{content}</p>
                <button onClick={() => this._chengeTitle('您點擊了按鈕,標題已經被修改')}>點擊</button>
            </div >
        )
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();

複製代碼
相關文章
相關標籤/搜索