React | React 與他的快樂小夥伴 Redux-事件處理(Handling events)
在上篇文章中,提到了 React 如何向 Redux 要求 store 中管理的資料,本篇會延續該篇文章內的程式碼接著說明,如果 React 要對資料進行異動,該怎麼做才好。
建立事件
其實建立事件並不難,首先在 Reducer 內部描述事件運作,再由 store 的內部函式 dispatch 讓 store 觸發 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 本身會回傳一個物件,包括了該函式會以何種名稱流進 component 的 props 中,以及使用 dispatch 觸發的對應函式產生的事件。
例如上方傳入的函式 changeName 會回傳一個 type 為 CHANGE_NAME 的物件,而該物件會藉由 dispatch 送往 Reducer 裡的 actions 接著執行。
將事件加入 component
在 component 內增加一個 button ,並將上方 mapDispatchToProps 需求單內指定流入 props 的事件名稱置於它的 onClick 中,並傳入要變更的參數 name 為 Rex ,讓待會點擊按鈕時可觸發變動 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 中觸發事件的生命週期如下:
- 以 store.dispatch()觸發事件。
- store會執行- dispatch的- function參數,並將- function的回傳值送至- Reducer的- action。
- Reducer會接收到- dispath觸發它,並根據- action的內容執行相對應的動作。
- store會儲存- Reducer回傳的新- state。
以上說明了如何在 Reducer 中描述事件執行,以及讓 React 的 component 透過 store.dispatch() 去觸發 Reducer ,最後得到新的 state 的過程。
此篇可能會稍微複雜一點,但其實也不只有一種方式可以處理事件,也可以不透過 Provider 直接在 component 中使用 dispatch 執行,這些也都會在後續的幾篇文章內提到。
如果以上內容有任何問題,或是不理解的地方,都歡迎留言告訴我,謝謝大家!
參考資料: