React Native之Redux使用詳解之Reducers(30)
React Native之Redux使用詳解之Reducers
一. Reducers
Actions 描述發生了什麼,但不能指定響應中state怎麼變化,這是Reducers的工作。
1. 設計State Shape
在Redux中,所有state儲存為一個單一物件。寫任何程式碼之前考慮好它的 Shape是一個好的注意。
對於我們的 todo 應用,我們想去儲存兩種不同事物:
- 當前所選的可見性過濾器
- todos 實際列表
你會發現在這個state樹中你需要儲存一些資料,以及一些UI狀態。但是必須保持資料和 UI 狀態分離。
{
visibilityFilter : 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
【注意 Relationships】
複雜應用中,分離不同實體,各個實體相互依賴。官方建議保持你的 state 儘可能規範沒有任何重疊。保持每個實體儲存在一個帶有ID作為key的物件中,通過IDs關聯其他實體或者列表。可以假定認為app的state作為資料庫。這個方式在
2. 操作Actions
如果現在已經確定好整個App的state物件, 接下來準備為App寫一個Reducer. 該Reducer 是一個以前一狀態數和一個action作為引數,返回新狀態的純函式.
(previousState,action) => newState
保持reducer純函式是非常重要,我們不應該在一個reducer中做以下操作:
- 複製傳入的引數
- 執行副作用操作,如 API 呼叫和路由轉換
呼叫非純函式, 如
Date.now()
或Math.random()
我將探索如何執行副作用在advanced walkthrough. 目前,我們只需記住reducer必須純淨. 它應該計算下一個狀態並返回. No surprises. No side effects. No API calls. No mutations. Just a calculation
我們逐漸寫一個reducer, 進而進一步理解之前提到的actions
我們以指定初始化狀態開始寫程式, Redux 第一次將傳入 undefined的state到我們定義的reducer. 這是返回該APP初始化狀態的時機.
Show your code:
import { VisibilityFilter} from './actions'
const initialState={
visibilityFilter: VisibilityFilter.SHOW_ALL,
todos:[]
}
function todo(state,action) {
if(typeof state === 'undefined') {
return initialState;
}
// For now, don't handle any actions, and just return the state given us.
return state;
}
function todo(state=initialState,action){
// For now, don't handle any actions,and just return the state given to us.
return state;
}
現在我們來操作 SET_VISIBILITY_FILTER
. 我們需要做的就是改變狀態visibilityFilter
function todo(state=initialState,action) {
switch(action) {
case 'SET_VISIBILITY_FILTER':
return Object.assign({},state,{
visibilityFilter:action.filter
})
default:
return state;
}
}
注意:
1. 我們沒有複製state
. 而是通過Object.assign()建立一個複製. Object.assign(state, {visibilityFilter: action.filter })是錯誤寫法: 該寫法將會複製第一個引數. 你也能學習object spread operator proposal 去寫這個 {…state, …newState}.
2.我們返回前一狀態在預設case.在一些未知的action情況下,我們需要返回前一狀態.
3.Object.assign()
Object.assign()是ES6語法,但是它仍然沒有被大多數瀏覽器實現, 開發者需要利用polyfill去寫Babel plugin,或者利用其他的庫,如_assign .
4.Note on switch and Boilerplate
The switch statement is not the real boilerplate. The real boilerplate of Flux is conceptual: the need to emit an update, the need to register the Store with a Dispatcher, the need for the Store to be an object (and the complications that arise when you want a universal app). Redux solves these problems by using pure reducers instead of event emitters.
It’s unfortunate that many still choose a framework based on whether it uses switch statements in the documentation. If you don’t like switch, you can use a custom createReducer function that accepts a handler map, as shown in “reducing boilerplate”.