Count items based on condition

徘徊边缘 提交于 2019-12-24 17:10:32

问题


The initial state of the store is:

let initialState = {
  items: [],
  itemsCount: 0,
  completedCount: 0
};

When I dispatch an action with the type ADD_ITEM the new item is added to the items array and itemsCount is incremented (Although I'm not sure if I'm doing it correctly)

case "ADD_ITEM": {
  return {
    ...state,
    items: [
      ...state.items,
      {
        title: action.name,
        dateCreated: action.date,
        id: action.id,
        isChecked: false
      }
    ],
    itemsCount: state.items.length + 1
  };
}

and for TOGGLE_ITEM

case "TOGGLE_ITEM": {
  return Object.assign({}, state, {
    items: state.items.map(item => {
      if (item.id !== action.id) {
        return item;
      }
      return Object.assign({}, item, {
        isChecked: !item.isChecked
      });
    })
  });
}

When I dispatch an action with the type REMOVE_ITEM the following is executed:

case "REMOVE_ITEM": {
  return Object.assign({}, state, {
    items: [...state.items.filter(item => item.id !== action.id)],
    itemsCount: state.items.length - 1
  });
}

Now I'm trying to count the items that have isChecked is true

state.items.map(item => {
    if(item.isChecked){
        //Increment count
    }
})

I'm not sure where exactly to do that.

Inside the TOGGLE_ITEM action?

Inside a new COUNT_ITEM action? if so, when is that action dispatched?

And how do assign an incremented digit to part of the state?


回答1:


You can just compute it when you need it in your actions/components etc:

items.filter(item => item.isChecked).length

It's not a good practice to store derived values such as the count of certain items (including the itemsCount variable) in your state (reasons similar to why you normalise your state).

If you are worried about performance (it's O(n) so shouldn't be much of an issue in general), you can use a memoization library.




回答2:


The count needs to be recalculated on TOGGLE_ITEM as well as ADD/REMOVE_ITEM. And the count reducer could use reduce like

state.items.reduce((acc, item) => {
    if(item.isChecked){
        acc += 1;
    }
    return acc;
}, 0)

However, you are better of not storing the COUNT in the reducer since it is directly derivable from items, you can simply calculate the count using a memoized selector in your mapStateToProps function. You could make use of reselect for writing memoized selectors or create your own




回答3:


Just a quick note, in order to reduce the extra overhead in your action code:

case "ADD_ITEM": {
  let items=state.items
  items.push({
      title: action.name,
      dateCreated: action.date,
      id: action.id,
      isChecked: false
    })
  return {
    ...state,
    items: items,
    itemsCount: state.itemsCount+1
  };
}


来源:https://stackoverflow.com/questions/50227082/count-items-based-on-condition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!