Home > front end >  Facing an error of "Too many renders ..."when trying to add a logic for checked items
Facing an error of "Too many renders ..."when trying to add a logic for checked items

Time:06-23

I am trying to build a shopping cart that takes items and quantities from a form input adding to local storage and displays them as a list of items in another component. Each list has a checkbox which on checking I want to move the item to the checked list. I am hitting an infinite rerender when trying to add logic to add checked items in a checked list. Here is my code: sandbox https://codesandbox.io/s/fervent-carson-gchmtt?file=/src/App.jsAny help in resolving an issue will be much appreciated.

ShoppingItemList.js

    import { React, useState, useCallback, useEffect } from "react";
import { Link } from "react-router-dom";
import "./ShoppingItemList.css";

const ShoppingItemList = (props) => {
  const [checked, setChecked] = useState(props.shoppingList);
  // useEffect(()=>{
  //   setChecked(props.shoppingList)
  // },[])
  // Add/Remove checked items from the list

  const handleCheck = useCallback(
    (index) => {
      let updatedList = [...props.shoppingList];
      updatedList[index].isSelected = !updatedList[index].isSelected;
      setChecked(updatedList);
      console.log("checked "   checked);
    },
    [checked]
  );
  return (
    <div className="container">
      <div className="title">Shopping List:</div>
      <div className="list-container">
        {props.shoppingList.map((item, index) => (
          <ul key={item.id}>
            <input value={item} type="checkbox" onChange={handleCheck(index)} />
            <div className="child">{item.item}</div>
            <div className="child">{item.quantity}</div>
          </ul>
        ))}
      </div>
      <Link to="/">Shopping Form</Link>
      <br></br>
      {/* <div>
        {`Items checked are: ${checkedItems}`}
      </div> */}
    </div>
  );
};
export default ShoppingItemList;

App.js

import { React, useState,useEffect } from "react";
import ShoppingListForm from "./Components/ShoppingListForm";
import ShoppingItemList from "./Components/ShoppingItemList";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
function App() {
  let initShoppingItemList = JSON.parse(localStorage.getItem("shoppedItem") || "[]");

  const [shoppingItem, setShoppingItem] = useState(initShoppingItemList);

  const addShoppedItemHandler = (shoppedItem) => {
  
    // const shoppingListWId = shoppingItem.map((n,i) => {
    // return n['id'] = i;  
    
    //    })
      
       let id;
    shoppingItem.length===0?id=0: id = shoppingItem[shoppingItem.length-1].id 1;

    const shoppingListWId = {
      id:id,
      item:shoppedItem.item,
      quantity:shoppedItem.quantity,
      isSelected:shoppedItem.isSelected
    };

    //setShoppingItem(...shoppingItem,shoppingListWId)
    
    setShoppingItem([...shoppingItem,shoppingListWId])

    // setShoppingItem((prevShoppingItem) => {
    //   return [shoppingItem, ...prevShoppingItem];
    // });
    console.log(shoppingItem);
  };
  useEffect(() => {
    if (initShoppingItemList !== 0)
      localStorage.setItem("shoppedItem", JSON.stringify(shoppingItem));
  },[initShoppingItemList,shoppingItem]);

  return (
    <Router>
      <Routes>
        <Route
          path="/"
          element={
            <ShoppingListForm onSavedShoppingData={addShoppedItemHandler} />
          }
        />
        <Route
          exact
          path="/itemList"
          element={<ShoppingItemList shoppingList={shoppingItem} />}
        />
      </Routes>
    </Router>
  );
}

export default App;

ShoppingListForm.js

import { React, useState } from "react";
import { useNavigate } from "react-router-dom";
import "./ShoppingListForm.css";

const ShoppingListForm = (props) => {
  const navigate = useNavigate();
  const [enteredItem, setEnteredItem] = useState("");
  const [enteredQuantity, setQuantity] = useState(0);

  const itemChangeHandler = (event) => {
    console.log("inputbox "   event.target.value);
    setEnteredItem(event.target.value);
  };

  const submitHandler = (event) => {
    event.preventDefault();
    let shoppingData;
    if (enteredItem !== undefined && enteredQuantity !== 0) {
      shoppingData = {
        item: enteredItem,
        quantity: enteredQuantity,
        isSelected: false
      };

      props.onSavedShoppingData(shoppingData);
      setEnteredItem("");
      setQuantity("");
      navigate("/itemList");
    } else {
      alert("Enter Item & select quantity");
    }
  };

  const dropdownChangeHandler = (event) => {
    console.log(event.target.value);
    setQuantity(event.target.value);
  };

  return (
    <form className="shop-item" onSubmit={submitHandler}>
      <div className="shop-item__controls">
        <div className="shop-item__control">
          <label>Title</label>
          <input
            type="text"
            value={enteredItem}
            placeholder="Add an item..."
            onChange={itemChangeHandler}
          />
        </div>
        <div className="shop-item__control">
          <label>Item Quantity</label>
          <select value={enteredQuantity} onChange={dropdownChangeHandler}>
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
        </div>
      </div>
      <div className="shop-item__actions">
        <button type="submit"> Save Item </button>
      </div>
    </form>
  );
};
export default ShoppingListForm;

CodePudding user response:

Your call in ShoppingList.js is wrong. Instead of onchange={handleCheck(index)} you need to make it an anonymous function to pass in an argument the way you have it: onChange={() => handleCheck(index)}`

Line 45 of ShoppingItemList.js

Your fixed sandbox: https://codesandbox.io/s/confident-wood-1jonhs

  • Related