Arrow functions and Event handling using useState()

My code displays an object having 4 items, which I fetch using { data }, with buttons next to each item to remove the particular item and button at the bottom to restore the list to its previous state.

import React from 'react';
import { data } from '../../../data';

const UseStateArray = () => {

  const [people, setPeople] = React.useState(data);
  
//button at the bottom to restore list to its entirety 
 const handleClick = () => {
    people.length < 4?setPeople(data):setPeople([]);
  }

//button to delete individual list items
  const handleClick2 = (id) =>{
    const newPeople = people.filter((person) => person.id !== id);
    setPeople(newPeople);
  }

  return (
    <>
    {people.map((person) => {
      const {id, name} = person;
      return (
        <div key = {id} className = 'item'>
          <h4>{name} </h4>
          <button className = "btn" onClick = {() => handleClick2(id)}> Click me to remove </button>
        </div>
      );
    })}

    <button className='btn' onClick={handleClick}>Click me to Restore</button>
    </>
  );
  };

export default UseStateArray;

I have defined an event handler function handleClick for the button at the bottom which restores the list to default which is :

const handleClick = () => {
    people.length < 4?setPeople(data):setPeople([]);
  }

If i call this function is this manner:

<button className='btn' onClick = {() => handleClick}>Click me to Restore</button>

Nothing happens. The list I generated does not go back to default.

the only way the button works is if i do:

<button className='btn' onClick={handleClick}>Click me to Restore </button>

whick is the opposite of what happens for the buttons I created for individual list items, they only work if i call handleClick2 as such:

onClick = {() => handleClick2(id)}

Why does this happen? The only reason i could find is because of this keyword binding. But I dont understand how that applies to this program I have.

When the useState hook is used to update a state based on the previous state the callback function should be provided with an argument (I usually call this prevState). I see that you are not using this pattern and I think there is a chance it may fix your problem.

See: https://reactjs.org/docs/hooks-reference.html#functional-updates

So you could do something like this in handleClick2:

  const handleClick2 = (id) =>{
    setPeople((people) => people.filter((person) => person.id !== id));
  }

Edit: actually I don’t think what I proposed will fix your problem. But it’s something to be aware of.

Ok, so here is what I think the click issue is. This works for you because you are invoking the function by calling it with a parenthesis after it where you pass in the id as a parameter:

onClick = {() => handleClick2(id)}

But here below you are creating an arrow function and you have handleClick in the body without using parenthesis after so the handleClick function is not invoked when arrow function is called:

onClick = {() => handleClick}

Finally, you also do this below. It works because you are attaching the function called handleClick to the onClick handler. If you look in this function body for handleClick it invokes the setPeople function with a parenthesis after:

const handleClick = () => {
    people.length < 4?setPeople(data):setPeople([]);
  }
<button className='btn' onClick={handleClick}>Click me to Restore </button>

Ok, so, what I understood is if we define an arrow function, then we have to include the parenthesis when we call another function from the arrow function else it would not be called?

So I can either write
onClick = {() => handleClick()}
or
onClick = {handleClick}
but, since my handleClick2 accepts an parameter, i cant write:

onClick = {handleClick2(id)}

I have to write

onClick = {() => handleClick2(id)}

is my understanding correct?

This top version would work but it’s not needed to wrap handleClick in an extra arrow function. So the second option is better as an extra unnecessary function is not created just to call another function. Here, the .map attaches the same function to the onClick attribute for all iterations of the array.

Where your function accepts a parameter:
onClick = {() => handleClick2(id)}
Here you have to create a function and use that to invoke handleClick2(id). You can’t do just handleClick2(id) because that kind of syntax tried to call the function here and now - we don’t want to call it, we want to create a list of divs. Your .map function will create (define) a separate function for each button that will call handleClick2 with the correct id. This is similar in a way to how you create an h4 with an individual name for each iteration of .map. When you call any function you always need to include the parenthesis. Without the parenthesis you can reference the function and pass it around, but not invoke it.