klaurtar1
klaurtar1

Reputation: 788

Checkbox set state, and reset in React

I am working on a checkbox component in React that is created from fetching group data from an API and then making a checkbox for each group. When you click a checkbox, I have set up the code to enter that specific group's ID into state in an array to be submitted with a form. My question has 2 parts. When i click a checkbox and unclick it, it enters the ID into state twice instead of removing the ID. How can I fix this?? Also, when I submit the form it is attached to I would like for the checkboxes to reset and basically unclick themselves and reset state to empty. How can i achieve this??

Here is my code:

import React, { useState, useEffect, useContext } from "react";
import { LoggedInContext } from "./contexts/LoggedIn";
import styles from "./styles/GroupCheckboxStyles";
import { withStyles } from "@material-ui/core";

function GroupCheckbox(props) {
  const [groups, setGroups] = useState([]);
  const [loading, setLoading] = useState(true);
  const { token } = useContext(LoggedInContext);
  const { classes } = props;

  useEffect(() => {
    fetch(process.env.REACT_APP_SERVER + "groups", {
      headers: {
        "Content-Type": "application/json",
        Token: token
      }
    })
      .then(res => res.json())
      .then(data => {
        setGroups(data.data);
        setLoading(false);
      });
  }, [token]);

  return (
    <div className={classes.root} style={{ margin: `${props.margin}` }}>
      <div className={classes.group_header}>Groups</div>
      {loading ? (
        <h1>Loading...</h1>
      ) : (
        groups.map(x => {
          return (
            <div className={classes.specific_group} key={x._id}>
              <input
                type="checkbox"
                id={x._id}
                name={x.name}
                onChange={props.handleGroupCheckboxClick}
              />
              <label htmlFor={x.name}>{x.name}</label>
            </div>
          );
        })
      )}
    </div>
  );
}

export default withStyles(styles)(GroupCheckbox);

And here is from the parent component passing down to it:

const handleGroupCheckboxClick = event => {
    let checkId = event.target.id;
    setSelectedGroups([...selectedGroups, checkId]);
    console.log(selectedGroups);
  };

<GroupCheckbox
          className={classes.checkbox}
          handleGroupCheckboxClick={handleGroupCheckboxClick}
          margin={"0 auto"}
        />

Here is an image of the checkbox component with it's log of state after clicking multiple times: State

Upvotes: 1

Views: 2254

Answers (1)

SILENT
SILENT

Reputation: 4268

Its easier with an object.

Change useState from array to object

...
const [selectedGroups, setSelectedGroups] = useState({});
...

Update handler

...
const handleGroupCheckboxClick = ({ target: { id }})=> {
    setSelectedGroups((s) => ({ ...s, [id]: !s[id] }));
  };
...

Then you can filter all true keys when submitting.

const keys = Object.keys(selectedGroups);
const arrayOfIds = [];
for(let i = 0; i<keys.length; i++) {
  const id = keys[i];
  if(selectedGroups[id]) arrayOfIds.push(id);
}
console.log({ arrayOfIds });

You can also connect the object to the checkboxes. When the object is renewed with a empty object, all checkboxes will be reset.

Upvotes: 2

Related Questions