/React, React Redux

React | React 與他的快樂小夥伴 Redux-事件處理(Handling events)

上篇文章中,提到了 React 如何向 Redux 要求 store 中管理的資料,本篇會延續該篇文章內的程式碼接著說明,如果 React 要對資料進行異動,該怎麼做才好。


建立事件

其實建立事件並不難,首先在 Reducer 內部描述事件運作,再由 store 的內部函式 dispatchstore 觸發 Reducer 執行,最後 Reducer 會儲存最後改變的 state 並將它回傳。

撰寫事件指令

Reducer 內會根據 action.type 來判斷要做什麼事情,因此為新事件定義一個指令:

const CHANGE_NAME = 'CHANGE_NAME'

雖然 ES6 新增了 const 來代表常式,但這裡指令還是用大寫,來代表不可變。

設定傳入 Reducer 的參數

上方提到 Reducer 必須靠傳入 action.type 的參數來判斷要執行什麼動作,以及執行此動作的額外參數,因此在執行事件時,得先設定傳入 Reducer 的物件:

const changeName = (name) => {
    return {
        type: CHANGE_NAME,
        payload: { 
            name: name 
        },
    }
}

changeName 回傳一個物件,該物件有兩個 key 第一個 type 代表該執行的事件為何, 進入 Reducer 時也會先判斷 type 的值, payload 則是執行事件的額外參數,上方的 name 就是在變更姓名這個事件執行時要傳入的參數。

在 Reducer 中描述事件

延續上篇的 Reducer ,在 switch 中增加 case 條件判斷,用來描述當 action.type 的值等於 CHANGE_NAME 時該做的事情,而 payload 會裡有額外參數,放置了 name 代表要改變的值:

const reducer = (state = initState, action) => {
    switch (action.type) {
        case CHANGE_NAME:
            return { 
                ...state, 
                name: action.payload.name 
            }
        default:
            return state
    }
}

這裡必須注意, CHANGE_NAME 內回傳的 state 並不是用原本的物件下去修改,而是用 ES6 的解構賦值回傳一個新物件(不熟悉 ES6 的話,物件和陣列分別可以用 Object.assign()Array.concat() )。

會這麼做是因為 Reducer 本身是一個純函數,所以藉由返回新的 state 來確保舊 state 原有的樣子是很重要的事情,而且如果直接修改回傳舊 state 的資料到 React 中的話,會導致 React 無法判別 state 的變化,也就不會重新 render 畫面。

填寫需求單

就算是事件,如果要透過 Provider 流進內部的 component 中,那就要填寫需求單,而事件和請求資料的需求單也稍微不同:

const mapDispatchToProps = dispatch => {
    return {
        changeName: name => dispatch(changeName(name))
    }
}

mapDispatchToProps 就是事件的需求單,本身擁有一個參數 dispatch ,是 store 的函式之一, dispatch 會將傳入它的參數送往 Reducer 中執行,而 mapDispatchToProps 本身會回傳一個物件,包括了該函式會以何種名稱流進 componentprops 中,以及使用 dispatch 觸發的對應函式產生的事件。

例如上方傳入的函式 changeName 會回傳一個 typeCHANGE_NAME 的物件,而該物件會藉由 dispatch 送往 Reducer 裡的 actions 接著執行。

將事件加入 component

component 內增加一個 button ,並將上方 mapDispatchToProps 需求單內指定流入 props 的事件名稱置於它的 onClick 中,並傳入要變更的參數 nameRex ,讓待會點擊按鈕時可觸發變動 state 中的 name ,並重新 render 畫面。

class ConnectTitle extends React.Component {
    render() {
        return (
            <div>
                <h1>Hello!{this.props.name}!</h1>
                <button onClick={this.props.changeName.bind(this,'Rex')}>
                    觸發事件
                </button>
            </div>
        )
    }
}

將 mapDispatchToProps 與 component 做連結

mapStateToProps 相同,透過 connect 函式處理需求單,不同的地方是 mapDispatchToProps 得放 connect 第二個參數的位置。

const Title = connect(mapStateToProps,mapDispatchToProps)(ConnectTitle)

最後讓運行應用程式,確認執行結果:


總結 Redux 中觸發事件的生命週期如下:

  1. store.dispatch() 觸發事件。
  2. store 會執行 dispatchfunction 參數,並將 function 的回傳值送至 Reduceraction
  3. Reducer 會接收到 dispath 觸發它,並根據 action 的內容執行相對應的動作。
  4. store 會儲存 Reducer 回傳的新 state

以上說明了如何在 Reducer 中描述事件執行,以及讓 Reactcomponent 透過 store.dispatch() 去觸發 Reducer ,最後得到新的 state 的過程。

此篇可能會稍微複雜一點,但其實也不只有一種方式可以處理事件,也可以不透過 Provider 直接在 component 中使用 dispatch 執行,這些也都會在後續的幾篇文章內提到。

如果以上內容有任何問題,或是不理解的地方,都歡迎留言告訴我,謝謝大家!

參考資料:

  1. https://blog.csdn.net/za_az/article/details/56483261
  2. https://chentsulin.github.io/redux/docs/basics/DataFlow.html