cycle4passion
cycle4passion

Reputation: 3321

React Trouble updating state with useReducer

Utilizing React useReducer and attempting to do state update and have react re-render as I make changes.

JSX calling the reducer:

<button onClick={() => dispatch({ type: "DECREMENT", item })} >+</button>

and the useReducer:

const reducer = (state, action) => {
  const { item, type } = action;
  switch (type) {
    case "INCREMENT": {
      const newCart = state;
      const u = { ...item, quantity: item.quantity + 1 };
      const index = newCart.findIndex(eachitem => item.id === eachitem.id);
      newCart.splice(index, 1, u);
      console.log("INCREMENT", newCart);
      return newCart;
    }
    case "DECREMENT": {
      const newCart = state;
      const u = { ...item, quantity: item.quantity - 1 };
      const index = newCart.findIndex(eachitem => item.id === eachitem.id);
      newCart.splice(index, 1, u);
      console.log("DECREMENT", newCart);
      return newCart;
    }
    case "REMOVE": {
      return state.filter(eachitem => item.id !== eachitem.id);
    }
    default: {
      return state;
    }
  }
};

Full code can be found below.

Edit codesandboxer-example

Upvotes: 1

Views: 2268

Answers (2)

GProst
GProst

Reputation: 10227

Your reducer can't detect the state change since you return the same object. The change is detected by comparing prev state value and new one, by === comparison or Object.is() comparison which is basically the same thing (not sure which one, can try to find in React docs).

So instead of:

const newCart = state;

You need to do:

// shallowly copy the state so now Object.is(newState, prevState) returns false
const newCart = [...state];
...
return newCart

Upvotes: 7

dance2die
dance2die

Reputation: 36895

You are setting the newCart as the state, which point to the same thing. Either you clone the state, or return a new object instance.

switch (type) {
    case "INCREMENT": {
      const newCart = state;
      const u = { ...item, quantity: item.quantity + 1 };
      const index = newCart.findIndex(eachitem => item.id === eachitem.id);
      newCart.splice(index, 1, u);
      console.log("INCREMENT", newCart);

      return [...newCart];
    }
    case "DECREMENT": {
      const newCart = state;
      const u = { ...item, quantity: item.quantity - 1 };
      const index = newCart.findIndex(eachitem => item.id === eachitem.id);
      newCart.splice(index, 1, u);
      console.log("DECREMENT", newCart);
      return [...newCart];
    }
    case "REMOVE": {
      return state.filter(eachitem => item.id !== eachitem.id);
    }
    default: {
      return state;
    }
  }
};

Updated SandBox Edit codesandboxer-example

Upvotes: 2

Related Questions