Home > Software engineering >  Why does the list render infinitely
Why does the list render infinitely

Time:11-20

I have two components - Contacts and ContactItem. In Contacts There is a div in which contacts are displayed and the "Add" button. In ContactItem there is a select with a choice of social network, textarea where you enter your number or nickname in the social network, the delete button. I need to implement the ability to remove and add new items

Now the problem is that I have an infinite number of renders when I click on the add button. How can it be fixed? enter image description here

const Contacts = () => {
  const [contactItems, setContactItems] = useState([
    {
      index: 0,
      key: 0,
      id: 0,
    },
  ]);

  const addItemHandler = (event) => {
    event.preventDefault();
    const id = uuidv4();
    setContactItems(() => [
      ...contactItems,
      {
        index: contactItems.length,
        key: id,
        id,
      },
    ]);
  };

  const removeItemHandler = (id) => {
    setContactItems((contactItems) =>
      contactItems.filter((el) => el.id !== id)
    );
  };

  return (
    <>
      <div className={stylesCenter.channels}>
        {contactItems.map((item) => (
          <ContactItem
            index={item.index}
            key={item.key}
            id={item.id}
            removeItem={removeItemHandler}
          />
        ))}
      </div>
      <div>
        <button
          onClick={addItemHandler}
        >
          <img src="plus.svg" alt="plus logo" />
        </button>
      </div>
    </>
  );
};

const ContactItem = ({ index, removeItem }) => {
  console.log("child render", index);
  return (
    <div className={stylescenter.fullChannelControll}>
        <select className={stylescenter.selecterOptions} name="optionSelected">
          {options.map((el) => (
            <option key={el.value} value={el.value}>
              {el.label}
            </option>
          ))}
        </select>
      <div className={stylescenter.detailsAndInputAndDelete}>
        <textarea
          maxLength="100"
          rows="2"
        />
        <div className={stylescenter.removeButtons}>
          {index !== 0 && (
            <span>
              <IconButton onClick={removeItem(index)}>
                <img src="bin.svg" alt="bin logo" />
              </IconButton>
            </span>
          )}
        </div>
      </div>
    </div>
  );
};

CodePudding user response:

You are actually passing the invocation of the function in the ContactItem component, inside the IconButton instead of the reference of the function that should be invoked onClick. Sounds tricky, but it's logic!

This way you are calling the function for each render of the component. Since the function makes a setState you are getting the issue.

To avoid this, you can convert your click handler into an arrow function like this:

<IconButton onClick={() => removeItem(index)}>
    <img src="bin.svg" alt="bin logo" />
</IconButton>

This way you pass the reference of the arrow function for each render!

CodePudding user response:

simply change this :

 <IconButton onClick={removeItem(index)}> 

to this :

 <IconButton onClick={()=> removeItem(index)}>

CodePudding user response:

You're directly calling removeItem function on IconButton onClick. So since you're updating your state in that function, your component gets re render forever ! The way you can solve the issue is this:

<IconButton onClick={() => removeItem(index)}>
  <img src="bin.svg" alt="bin logo" />
</IconButton>
  • Related