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
執行,這些也都會在後續的幾篇文章內提到。
如果以上內容有任何問題,或是不理解的地方,都歡迎留言告訴我,謝謝大家!
參考資料: