整個應用的state被儲存在一棵object tree中,并且這個object tree只存在于唯一個store中。來自于服務器端的state也可以序列化之后直接注入客戶端中
console.log(store.getState()) //輸出 { visibility: 'SHOW_ALL', todos: [ { text: 'using redux', completed: true }, { text: 'keep all state in a single tree', completed: false } ] }唯一改變state的方法就是觸發action,action是一個用于描述已發生事件的普通對象。 這樣確保了視圖和網絡請求都不能直接修改state,它們只能觸發一個action,至于是否修改state,由action的集中處理決定。action嚴格按照先后順序執行,不用擔心race condition競態條件。action是普通對象,可以被日志打印,序列化等等,相當于可以自定義的event
store.dispatch({ //action的type屬性為大寫,是action的區分標識 type: 'COMPLETE_TODO', //可以附帶其他key:value鍵值對 index: 1 }) store.dispatch({ //下文reducer中用到 type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED' })實際開發中,當我使用localstorage對state進行持久化存儲時,不能通過直接清除localstorage來刪除某一個state,而應該觸發一個DELETE的action來清除state
reducer是一些純函數,接收先前的state和action,并返回新的state,剛開始可以只有一個reducer,當應用變大的時候,可以根據業務邏輯拆分成多個reducer,分別操作state tree的不同部分,
function visibilityFilter(state='SHOW_ALL', action){ switch(action.type){ //上文的action case 'SET_VISIBILITY_FILTER': //返回狀態 return action.filter default: return state } }Action是把數組從應用傳到store層的載體,它是store數據的唯一來源,添加新todo任務的action是這樣的:
const ADD_TODO = 'ADD_TODO' { type: ADD_TODO, text: '' }創建一個action需要action創建函數
function addTodo(text){ return { type: ADD_TODO, text: '' } }觸發一次action則是發起一次dispatch過程
diapatch(addTodo(text))也可以創建一個變量動態綁定
const boundAddTodo = (text) => dispatch(addTodo(text)) //相當于boundAddTodo = function(text){ return dispatch(addTodo(text)) }所以可以直接調用
boundAddTodo(text);action 來描述“發生了什么”, reducers 根據 action 更新 state,而store就是把它們聯系到一起的對象,Store有以下職責 1. 維持應用的state 2. 提供getState()方法獲取當前state 3. 提供dispatch(action)方法更新state 4. 通過subscribe(listener)注冊監聽器 5. 通過subscribe(listener)返回的函數注銷監聽器 redux應用只有單一的store, 當需要拆分數據處理邏輯時,應該使用 reducer 組合而不是創建多個 store。
redux的數據流遵循以下4個步驟 1. 調用store.dispatch(action),可以在任何地方調用 store.dispatch(action),包括組件中、XHR 回調中、甚至定時器中。 2. Store 會把兩個參數傳入 reducer: 當前的 state 樹和 action 3. Redux 原生提供combineReducers()輔助函數,來把根 reducer 拆分成多個函數,用于分別處理 state 樹的一個分支。
function todos(state = [], action) { // 省略處理邏輯... return nextState; } function visibleTodoFilter(state = 'SHOW_ALL', action) { // 省略處理邏輯... return nextState; } //拆分后將多個函數合并 let todoApp = combineReducers({ todos, visibleTodoFilter })Redux store 保存了根 reducer 返回的完整 state 樹。開發復雜的應用時,不可避免會有一些數據相互引用。盡可能地把 state 范式化,不存在嵌套。把所有數據放到一個對象里,每個數據以 ID 為主鍵,不同實體或列表間通過 ID 相互引用數據。把應用的 state 想像成數據庫。例如,實際開發中,在 state 里同時存放 todosById: { id -> todo } 和 todos: array 是比較好的方式 另外,在return state的時候
return Object.assign({}, state, { visibilityFilter: action.filter })不要修改state, 不能使用 Object.assign(state, { visibilityFilter: action.filter }),因為它會改變第一個參數的值。
新聞熱點
疑難解答