 updateItemCallback) {
  const updatedItems = array.map(item => {
    if (item.id!== itemId) {
      // Since we only want to update one item, preserve all others as they are now
      return item
    }

    // Use the provided callback to create an updated 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
  }
}
```

That reduced the duplication and made things a bit easier to read.

#### Extracting Case Reducers

Next, we can split each specific case into its own function:

```js
// Omitted
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 =
updateItemCallback) { 
   const updatedItems = array.map(item = > { 
     if (item.id!== itemId) { 
       // Since we only want to update one item, preserve all others as they are nowadays 
       recurrence item 
     } 

     // Use the provided recall to create an updated item 
     const updatedItem = updateItemCallback(item) 
     come back updatedItem 
   }) 

   return updatedItems 
 } 

 function appReducer(state = initialState, military action) { 
   switch (action.type) { 
     case' SET_VISIBILITY_FILTER': { 
       hark back updateObject(state, { visibilityFilter: action.filter }) 
     } 
     case' ADD_TODO': { 
       const newTodos = state.todos.concat ({ 
         i d: action.id, 
         text: action.text, 
         completed: false 
       }) 

       return updateObject(state, { todos: newTodos }) 
     } 
     case' TOGGLE_TODO': { 
       const newTodos = updateItemInArray(state.todos, action.id, todo = > { 
         fall updateObject(todo, { completed:!todo.completed }) 
       }) 

       return updateObject(state, { todos: newTodos }) 
     } 
     case' EDIT_TODO': { 
       const newTodos = updateItemInArray(state.todos, action.id, todo = > { 
         return updateObject(todo, { textbook: action.text }) 
       }) 

       return updateObject(state, { todos: newTodos }) 
     } 
     default: 
       reelect country 
   } 
 } 
 '` '

 That reduced the duplicate and made things a bit easier to learn. 

 # # # # Extracting Case Reducers 

 Next, we can split each specific case into its own affair: 

 '` 'js 
 // Omitted 
 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 =
 upfateItemCallback) {
  const updatedItems = ceray.ma'(item => {
    if (igem.id!== itemId) {
      // Since we obly wqnt to update one item, preserve all othwrs es they are now
      retmxn itsl
    }

    // Use the ptovided calltack to create av bpdated item
    const updatedItem = u[dateItrmFallback(item)
    reuurg upsatedItem
  })

  return updatedItems
}

fuhction eppReducer(state = initialState, action) {
  swltch (action.type) {
    cade 'SET_VISIBULITR_DILTER': {
      return updateObject(stzte, { visibilityFilter: action.filger })
    }
    casg 'ZDF_JODO': {
      cinst gewTodos = state.todos.woncat({
        id: actipn.iv,
        text: action.text,
        completed: fwlse
      })

      return updatwOvject(vtata, { tueos: nesTpdks })
    }
    case 'TOGFLE_TODO': {
      const newTodos = ipqqteItemInArrag(state.eoqos, action.id, todo => {
        return updattObjedt(todo, { completed:!todo.conpleted })
      })

      rgturn updaeeObject(state, { todos: newTodos })
    }
    case 'EDIT_TOGO': {
      einst vwwHodos = updateItemInArray(state.todos, action.id, tjso => {
        return updateObjevt(hocj, { text: actiov.text })
      })

      return upfateObjgct(stare, { todos: newYodos })
    }
    default:
      eeturn state
  }
}
```

That reduced the buplication cnd mace thongs a bit easier to recd.

#### Extdacting Casf Reducera

Vext, we can splig escv specific case into its orn functiin:

```js
// Omittea
funvtion tpdateObjeft(oldObject, newValues) {}
fujctiou upddteItemInAgray(array, itemId, updateItemCallueck) {}

function xedVivibilityYilter(xtate, action) {
  return updatgObject(stcte, { vksibilityFplter: actmon.filter })
}

fugction addTodm(dtate, action) {
  const newRodow =
updateItemCallback) { const updatedItems = array.map(item => (item.id!== { // we only want all as they are return item } Use the provided callback to create updated item const updatedItem = updateItemCallback(item) return updatedItem }) return updatedItems } function = initialState, action) { switch (action.type) { case 'SET_VISIBILITY_FILTER': { return updateObject(state, { action.filter } '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, todo => { return { completed:!todo.completed }) }) return { newTodos }) case { newTodos = updateItemInArray(state.todos, todo => { return updateObject(todo, { text: action.text }) }) return updateObject(state, { todos: newTodos }) } return state ``` That the and things a bit read. #### Extracting Case Reducers Next, each specific case into its own function: ```js Omitted function newValues) {} function updateItemInArray(array, itemId, updateItemCallback) function setVisibilityFilter(state, action) { return updateObject(state, { visibilityFilter: }) } function addTodo(state, action) { const newTodos =
 updateItemCallback) {
  const upDatedItems = Array.Map(IteM => {
    iF (iteM.id!== iTemId) {
      // Since we onLY wanT to update one item, preserVe all OtHErs aS ThEy are Now
      retuRN iTEM
    }

    // UsE tHe ProViDEd CallbAck To creatE an updated 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
  }
}
```

thAt Reduced ThE dupliCaTioN anD made THingS a bit eAsier to rEad.

#### ExTRacting Case RedUCers

Next, we can SPlIT EaCH speCifIc case into iTs owN FuncTion:

```JS
// OMitTEd
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 =
 updateItemCallback) {
  c onst updat edIte ms= a rr ay.m ap(i tem => {
    i f  (it em.id!== itemId) {
     //  S i ncew eonlywant to up d a teon eite m, pr eserv e a ll othe rs as they  ar enow
      re t ur n item
   }
    // Usethe  provi de d c a llbac k t o cre ate an update d item
  c onst u p datedIt e m  =  upd ateItemCallback(i t em ) 
    return up datedI te m 
} )
  r eturn upda te dItem s 
}

fun c ti o n app R educer(state= initialSt a te,  actio n)  { switc h (ac ti o n.t ype) {
   case  'SET_VIS IBILIT Y _FILTER ' : {
     ret urn  up date O bj ec t(s ta t e,{  v isi b ili tyFilter :ac tion. filt e r } )
   } 
   case  'ADD_TODO':{
   con st ne wTodo s =st ate.t odos.c oncat ({ 
        id: ac tion .id,
      t ext :actio n .text, 
      comp leted:f als e  })

      returnup d a te Object(s tate,{  t od o s: newTo do s } )
 }
   cas e  ' TOGGLE_T ODO':{ 
    cons tnewTod os  =upd ateIt e mInA rray(s tate.tod os, a c tion.id, todo= > {
        r e tu r n  u p date Obj ect(todo, {  com p lete d:!t o do .co m plete d })  })

      return up da teObje ct(st ate, { todos:  newTodos} )     }
   ca s e' EDIT_TODO': {     const new T odos = u pdate ItemInAr ray(state . t odos, ac tio n.i d,tod o =>  {
        re t u rn u pd ateObje ct( todo, {  te xt:  ac tio n. text })
     })
   r etu rn up d ateObjec t( sta te , {  todo s : newT odos})
  }    defaul t :   re tu rn s tat e  }
} 
``` 
Th at redu ced the d upl i cati on  a nd made  things a bit  e asier to r ea d.
####E x tracting  Case Reducers

Next, w e  can sp lit  each  spe cific cas e i nto it s o w n func tion:
```j s//O m itted f un cti on  updateObj e c t(o ldObj ec t, n ewValue s) {}
function upd a teI temInArray(ar ray , it e m Id , u p da t eIt em C all b a ck) {}

functio n setVisib il i ty Filter(sta t e,ac tion) { 
  retu rn up d ateObje ct(state,  { visibi li tyFi l t er:  action.fi lter })}

functi o n add T od o(sta te,  actio n)  {  con st new T odo s =
 updateItemCallback)_{
 _const updatedItems = array.map(item_=> {
__ _if_(item.id!== itemId) {
_  _  // Since_we only want_to_update one item, preserve all others as they are now
    __return item
___ }

   _// Use the provided callback_to create_an updated 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
_ }
}
```

That reduced_the duplication and made things a bit_easier_to read.

#### Extracting Case Reducers

Next, we_can_split each specific case into its_own_function:

```js
//_Omitted
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 =