Viet
Viet

Reputation: 6953

Why my check box isn't updated after click?

I'm trying to use React Hooks to update the list of items. When users click on the check-box, the app should render the items which have been selected as purchased.

I could log the event of the handPurchase() and the state is correct, however, I can't make the function render the latest state.

With class, I can do:

const handlePurchase() {
  // ...
  this.setState(updatedGroceries);
}

this.state.groceries.map(//...render list

This is the code:

export default function CheckboxList() {
    let initialGroceries = [
        {
            id: "one",
            text: "Apple",
            purchased: false
        },
        {
            id: "two",
            text: "Banana",
            purchased: false
        }
    ];
    const [groceries, setGroceries] = useState(initialGroceries);

    const handlePurchase = (id: string) => () => {
        groceries.forEach((item) => {
            if (item.id === id) {
                item.purchased = true;
            }
        });
        setGroceries(groceries);   
    }

    return (
      <List>
        {groceries.map((item) => {
          const labelId = `checkbox-list-label-${item.id}`;

          return (
            <ListItem key={item.id} role={undefined} dense button onClick={handlePurchase(item.id)}>
              <ListItemIcon>
                <Checkbox
                  checked={item.purchased}
                  inputProps={{ 'aria-labelledby': labelId }}
                />
              </ListItemIcon>
              <ListItemText id={labelId} primary={item.text} />
            </ListItem>
          );
        })}
      </List>
    );
}

Also, if I do this:

const updatedGroceries = groceries.forEach((item) => {
            if (item.id === id) {
                item.purchased = true;
            }
        });
        setGroceries(updatedGroceries);   

I get this error:

Argument of type 'void' is not assignable to parameter of type 'SetStateAction<{ id: string; text: string; purchased: boolean; }[]>'. TS2345

Upvotes: 0

Views: 72

Answers (1)

norbitrial
norbitrial

Reputation: 15166

The issue is that forEach does not return anything as you might expect. I guess you would like to update with setGroceries the purchased property on the elements where the provided id is equals to the current one to true. So you need to return an array for example with Array.prototype.map(). From the documentation:

The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

I guess the following can work for you:

const updatedGroceries = groceries.map((item) => {
  if (item.id === id) {
    item.purchased = true;
  }

  return item;
});

setGroceries(updatedGroceries);   

In your code you were assigning to updatedGroceries the forEach result which is undefined because it does not return anything, find here in the docs.

I hope that helps!

Upvotes: 2

Related Questions