<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 使用函數分解(Functional Decomposition)和 Reducer 組合(Reducer Composition)重構 Reducer 看看不同類型的 `sub-reducer` 和如何把他們組合在一起的例子是很有用的。現在讓我們看看如何將一個大型的單個 reducer 重構為多個比較小的函數的組合。 > 注意: 為了說明重構的概念和過程而不是為了編寫簡潔的代碼,這個例子是特意以冗長的風格編寫的 #### 初遇 Reducer 讓我們看看初始 reducer 長什么樣: ```javascript const initialState = { visibilityFilter: 'SHOW_ALL', todos: [] } function appReducer(state = initialState, action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': { return Object.assign({}, state, { visibilityFilter: action.filter }) } case 'ADD_TODO': { return Object.assign({}, state, { todos: state.todos.concat({ id: action.id, text: action.text, completed: false }) }) } case 'TOGGLE_TODO': { return Object.assign({}, state, { todos: state.todos.map(todo => { if (todo.id !== action.id) { return todo } return Object.assign({}, todo, { completed: !todo.completed }) }) }) } case 'EDIT_TODO': { return Object.assign({}, state, { todos: state.todos.map(todo => { if (todo.id !== action.id) { return todo } return Object.assign({}, todo, { text: action.text }) }) }) } default: return state } } ``` 這個函數非常短,但已經開始變得比較復雜。我們在處理兩個不同的區域(filtering 和 todo 列表),嵌套使得更新邏輯難以閱讀,并且會讓我們不清楚到底是什么跟什么。 #### 提取工具函數(Extracting Utility Functions) 第一步是寫一個返回更新了相應區域的新對象。這兒還有一個重復的邏輯是在更新數組中的特定項目,我們也可以將他提成一個函數。 ```javascript function updateObject(oldObject, newValues) { // 用空對象作為第一個參數傳遞給 Object.assign,以確保是復制數據,而不是去改變原來的數據 return Object.assign({}, oldObject, newValues) } function updateItemInArray(array, itemId, updateItemCallback) { const updatedItems = array.map(item => { if (item.id !== itemId) { // 因為我們只想更新一個項目,所以保留所有的其他項目 return item } // 使用提供的回調來創建新的項目 const updatedItem = updateItemCallback(item) return updatedItem }) return updatedItems } function appReducer(state = initialState, action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': { return updateObject(state, { visibilityFilter: action.filter }) } case 'ADD_TODO': { const newTodos = state.todos.concat({ id: action.id, text: action.text, completed: false }) return updateObject(state, { todos: newTodos }) } case 'TOGGLE_TODO': { const newTodos = updateItemInArray(state.todos, action.id, todo => { return updateObject(todo, { completed: !todo.completed }) }) return updateObject(state, { todos: newTodos }) } case 'EDIT_TODO': { const newTodos = updateItemInArray(state.todos, action.id, todo => { return updateObject(todo, { text: action.text }) }) return updateObject(state, { todos: newTodos }) } default: return state } } ``` 這樣就減少了重復,使得代碼的可讀性更高。 #### 提取 case reducer 接下來,把特殊邏輯封裝成對應的函數: ```javascript // 省略了內容 function updateObject(oldObject, newValues) {} function updateItemInArray(array, itemId, updateItemCallback) {} function setVisibilityFilter(state, action) { return updateObject(state, { visibilityFilter: action.filter }) } function addTodo(state, action) { const newTodos = state.todos.concat({ id: action.id, text: action.text, completed: false }) return updateObject(state, { todos: newTodos }) } function toggleTodo(state, action) { const newTodos = updateItemInArray(state.todos, action.id, todo => { return updateObject(todo, { completed: !todo.completed }) }) return updateObject(state, { todos: newTodos }) } function editTodo(state, action) { const newTodos = updateItemInArray(state.todos, action.id, todo => { return updateObject(todo, { text: action.text }) }) return updateObject(state, { todos: newTodos }) } function appReducer(state = initialState, action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': return setVisibilityFilter(state, action) case 'ADD_TODO': return addTodo(state, action) case 'TOGGLE_TODO': return toggleTodo(state, action) case 'EDIT_TODO': return editTodo(state, action) default: return state } } ``` 現在很清楚每個 `case` 發生了什么。我們也可以看到一些模式的雛形。 #### 按域拆分數據(Separating Data Handling by Domain) 目前的 Reducer 仍然需要關心程序中所有不同的 case。下面嘗試把 filter 邏輯和 todo 邏輯分離: ```javascript // 省略了內容 function updateObject(oldObject, newValues) {} function updateItemInArray(array, itemId, updateItemCallback) {} function setVisibilityFilter(visibilityState, action) { // 從技術上將,我們甚至不關心之前的狀態 return action.filter } function visibilityReducer(visibilityState = 'SHOW_ALL', action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': return setVisibilityFilter(visibilityState, action) default: return visibilityState } } function addTodo(todosState, action) { const newTodos = todosState.concat({ id: action.id, text: action.text, completed: false }) return newTodos } function toggleTodo(todosState, action) { const newTodos = updateItemInArray(todosState, action.id, todo => { return updateObject(todo, { completed: !todo.completed }) }) return newTodos } function editTodo(todosState, action) { const newTodos = updateItemInArray(todosState, action.id, todo => { return updateObject(todo, { text: action.text }) }) return newTodos } function todosReducer(todosState = [], action) { switch (action.type) { case 'ADD_TODO': return addTodo(todosState, action) case 'TOGGLE_TODO': return toggleTodo(todosState, action) case 'EDIT_TODO': return editTodo(todosState, action) default: return todosState } } function appReducer(state = initialState, action) { return { todos: todosReducer(state.todos, action), visibilityFilter: visibilityReducer(state.visibilityFilter, action) } } ``` 我們注意到,兩個 reducer 分別關心 state 中的不同的部分。都只需要把自身關心的數據作為參數,不再需要返回復雜的嵌套型 state 對象了,代碼變得更簡單。 #### 減少樣板代碼 馬上就大功告成了。因為很多人不喜歡使用 switch 這種語法結構,創建一個 action 到 case 查找表示非常通用的做法。可以使用 [縮減樣板代碼](./ReducingBoilerplate.md#generating-reducers) 中提到的 `createReducer` 函數減少樣板代碼。 ```javascript // 省略了內容 function updateObject(oldObject, newValues) {} function updateItemInArray(array, itemId, updateItemCallback) {} function createReducer(initialState, handlers) { return function reducer(state = initialState, action) { if (handlers.hasOwnProperty(action.type)) { return handlers[action.type](state, action) } else { return state } } } // 省略了內容 function setVisibilityFilter(visibilityState, action) {} const visibilityReducer = createReducer('SHOW_ALL', { SET_VISIBILITY_FILTER: setVisibilityFilter }) // 省略了內容 function addTodo(todosState, action) {} function toggleTodo(todosState, action) {} function editTodo(todosState, action) {} const todosReducer = createReducer([], { ADD_TODO: addTodo, TOGGLE_TODO: toggleTodo, EDIT_TODO: editTodo }) function appReducer(state = initialState, action) { return { todos: todosReducer(state.todos, action), visibilityFilter: visibilityReducer(state.visibilityFilter, action) } } ``` #### 通過切片組合 Reducer(Combining Reducers by Slice) 最后一步了,使用 Redux 中 `combineReducers` 這個工具函數去把管理每個 state 切片的邏輯組合起來,形成頂層的 reducer。最終變成這樣: ```javascript // 可重用的工具函數 function updateObject(oldObject, newValues) { // 將空對象作為第一個參數傳遞給 Object.assign,以確保只是復制數據,而不是去改變數據 return Object.assign({}, oldObject, newValues) } function updateItemInArray(array, itemId, updateItemCallback) { const updatedItems = array.map(item => { if (item.id !== itemId) { // 因為我們只想更新一個項目,所以保留所有的其他項目 return item } // 使用提供的回調來創建新的項目 const updatedItem = updateItemCallback(item) return updatedItem }) return updatedItems } function createReducer(initialState, handlers) { return function reducer(state = initialState, action) { if (handlers.hasOwnProperty(action.type)) { return handlers[action.type](state, action) } else { return state } } } // 處理特殊 case 的 Handler ("case reducer") function setVisibilityFilter(visibilityState, action) { // 從技術上將,我們甚至不關心之前的狀態 return action.filter } // 處理整個 state 切片的 Handler ("slice reducer") const visibilityReducer = createReducer('SHOW_ALL', { SET_VISIBILITY_FILTER: setVisibilityFilter }) // Case reducer function addTodo(todosState, action) { const newTodos = todosState.concat({ id: action.id, text: action.text, completed: false }) return newTodos } // Case reducer function toggleTodo(todosState, action) { const newTodos = updateItemInArray(todosState, action.id, todo => { return updateObject(todo, { completed: !todo.completed }) }) return newTodos } // Case reducer function editTodo(todosState, action) { const newTodos = updateItemInArray(todosState, action.id, todo => { return updateObject(todo, { text: action.text }) }) return newTodos } // Slice reducer const todosReducer = createReducer([], { ADD_TODO: addTodo, TOGGLE_TODO: toggleTodo, EDIT_TODO: editTodo }) // 頂層 reducer const appReducer = combineReducers({ visibilityFilter: visibilityReducer, todos: todosReducer }) ``` 現在我們有了分離集中 reducer 的例子:像 `updateObject` 和 `createReducer` 一樣的工具函數,像 `setVisibilityFilter` 和 `addTodo` 一樣的處理器(Handler),像 `visibilityReducer` 和 `todosReducer` 一樣的處理單個切片數據的 Handler。`appReducer` 可以被當作是頂層 reducer。 這個例子中最后的結果看上去比原始的版本更長,這主要是因為工具函數的提取,注釋的添加和一些為了清楚起見的故意冗長(比如單獨的 return 語句)。單獨的看每個功能,他們承擔的責任更小,意圖也更加清楚。在真正的應用中,這些函數將會分到單獨的文件中,比如:`reducerUtilities.js`,`visibilityReducer.js`,`todosReudcer.js` 和 `rootReducer.js`。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看