reactjsreact-hooksuse-effectreducersuse-context

A mistake causes the function to be rendered infinity


I tried to add a button to my code, To change some properties of an array by clicking on it. To do this, I used Context and Reducer. But there is a problem! When I comment the dispatch, the problem is solved and the function is rendered only once. but when I use Reducer, the function rendered infinite times! please help me :( It is worth mentioning that this reducer has been used in other components, but this problem has not occurred.

App.js : (only reducer)

 const [goodsState, goodsDispatch] = useReducer(GoodsReducer, {
    goods: [
      {name : 'x', price : 126000, selected : false, key : 1},
      {name : 'y', price : 123000, selected : false, key : 2},
      {name : 'z', price : 126000, selected : false, key : 3},
          ]
  });

Cart.js :

import React, { useContext } from "react";
import GoodsContext from "../Contexts/GoodsContext";

export default function Cart(){
  const goodsContext = useContext(GoodsContext);
  const selectItem = (key) => {
  goodsContext.goodsDispatch({ type: "buy-item", payload: { key: key } });
};

return (
      <div>
        <h1>{selected[0].name}</h1>
        <h1>{selected[0].price}</h1>
        <button onClick={selectItem(selected[0].key)}>+</button>
        //some cod
      </div>
    );
};

GoodsReducer.js :

export default function GoodsReducer(state, action) {
  switch (action.type) {
    case "buy-item":
      return buyItem(state, action);

    default:
      return state;
  }
}

const buyItem = (state, action) => {
  let key = action.payload.key;
  changedGoods.selected = true;
  const otherGoods = state.goods.filter((good) => good.key !== key);
  return {
    ...state,
    goods: [...otherGoods, changedGoods]
  };
};


Solution

  • You have to add a Callback to your onClick:

    onClick={() => selectItem(selected[0].key)}
    

    Otherwise the selectItem will be called on every render, resulting in an infinte loop of renders. It has nothing to do with useReducer.