简体   繁体   中英

How to implement a check all button for radio buttons, using React Hooks?

Don't get this confused with checking each radio button I have on the page. I want to implement a check all button that sets the value of a nested object state equal to a certain value. I am storing each question in a nested state. Ex.

formQuestions({ 
  kitchen: [question,question2,question3],
  living: [question,question2,question3]
})

Four radio buttons are being made for each question. Now one radio button can only be selected at once. Each radio button has its' own value. Ex. `"Good", "Fair", "Poor", "N/A".

When a radio button is selected a state is generated dynamically for that section and question. Ex.

formAnswers({
  kitchen: {
    question: "Good"
    question2: "Poor"
  }
})

The goal here is the button that I want to create that checks only one value for each question Ex. clicks button question: "Good", question2: "Good" etc..

For me to set the state of a dynamic value I would need the "Section name" lets call it Name and the "Question" we'll call it question . That would give me access to the value like so formAnswers[Name][question]: value

I am trying to set that state from a component called SectionHeader . These contain the buttons.

SectionHeader.js

import { FormAnswersContext, FormQuestionsContext } from "../../Store";

function SectionHeader({ title, name }) {
  const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
  const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);

  return (
    <div>
      <h1 className={styles["Header"]}>{title}</h1>
      <div className={styles["MarkAllWrapper"]}>
        <button className={styles["MarkAll"]}>
          Mark all items as "Good" in this section
        </button>
        <br />
        <button className={styles["MarkAll"]}>
          Mark all items as "N/A" in this section
        </button>
      </div>
    </div>
  );
}

The parent of Section Header and the rest of the form code excluding the child radio buttons which I have explained, are in another component LivingRoom.js

LivingRoom.js

import { FormQuestionsContext, FormAnswersContext } from "../../Store";

function LivingRoomForm({ Name }) {
  const [expanded, setExpanded] = useState(false);
  const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
  const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
  const array = formQuestions.living;
  const onChange = (e, name) => {
    const { value } = e.target;
    setFormAnswers((state) => ({
      ...state,
      [Name]: { ...state[Name], [name]: value },
    }));
  };
  const handleOpen = () => {
    setExpanded(!expanded);
  };
  return (
    <div>
      <Button
        className={styles["CollapseBtn"]}
        onClick={handleOpen}
        style={{ marginBottom: "1rem", width: "100%" }}
      >
        <p>LIVING ROOM INSPECTION</p>
        <FontAwesome
          className="super-crazy-colors"
          name="angle-up"
          rotate={expanded ? null : 180}
          size="lg"
          style={{
            marginTop: "5px",
            textShadow: "0 1px 0 rgba(0, 0, 0, 0.1)",
          }}
        />
      </Button>
      <Collapse className={styles["Collapse"]} isOpen={expanded}>
        <Card>
          <CardBody>
            {array ? (
              <div>
                <SectionHeader title="Living Room Inspection" name={Name} />
                <div
                  className={styles["LivingRoomFormWrapper"]}
                  id="living-room-form"
                >
                  {array.map((question, index) => {
                    const selected =
                      formAnswers[Name] && formAnswers[Name][question]
                        ? formAnswers[Name][question]
                        : "";
                    return (
                      <div className={styles["CheckboxWrapper"]} key={index}>
                        <h5>{question}</h5>
                        <Ratings
                          section={Name}
                          question={question}
                          onChange={onChange}
                          selected={selected}
                        />
                      </div>
                    );
                  })}
                </div>
                <br />
                <ImageUploader name="living" title={"Living Room"} />
              </div>
            ) : (
              <div></div>
            )}
          </CardBody>
        </Card>
      </Collapse>
    </div>
  );
}

If there is anything I am missing please let me know, I would be happy to share it. Cheers

Edit: for anyone that needs the radio buttons component.

Ratings.js

import React from "react";
import { FormGroup, CustomInput } from "reactstrap";

function Ratings({ selected, section, question, onChange }) {
  return (
    <div>
      <FormGroup>
        <div>
          <CustomInput
            checked={selected === "Good"}
            onChange={(e) => onChange(e, question)}
            type="radio"
            id={`${section}_${question}_Good`}
            value="Good"
            label="Good"
          />
          <CustomInput
            checked={selected === "Fair"}
            onChange={(e) => onChange(e, question)}
            type="radio"
            id={`${section}_${question}_Fair`}
            value="Fair"
            label="Fair"
          />
          <CustomInput
            checked={selected === "Poor"}
            onChange={(e) => onChange(e, question)}
            type="radio"
            id={`${section}_${question}_Poor`}
            value="Poor"
            label="Poor"
          />
          <CustomInput
            checked={selected === "N/A"}
            onChange={(e) => onChange(e, question)}
            type="radio"
            id={`${section}_${question}_NA`}
            value="N/A"
            label="N/A"
          />
        </div>
      </FormGroup>
    </div>
  );
}

I do not completely understand your question, I am sorry but I think this will help you. Here is an implementation of radio buttons using react -

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleChange = e => {
    const { name, value } = e.target;

    this.setState({
      [name]: value
    });
  };

  render() {
    return (
      <div className="radio-buttons">
        Windows
        <input
          id="windows"
          value="windows"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
        Mac
        <input
          id="mac"
          value="mac"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
        Linux
        <input
          id="linux"
          value="linux"
          name="platform"
          type="radio"
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

After a few attempts, I was able to figure out the solution to this issue.

The key here was to figure out a way to get gather each question so that it may be used as a key when setting the state. As my questions were stored in a ContextAPI, I was able to pull them out like so...

this may not be the best solution however it worked for me.

  const setStateGood = () => {
    formQuestions[name].map((question) => {
      setFormAnswers((state) => ({
        ...state,
        [name]: { ...state[name], [question]: "Good" },
      }));
    });
  };
  const setStateNA = () => {
    formQuestions[name].map((question) => {
      setFormAnswers((state) => ({
        ...state,
        [name]: { ...state[name], [question]: "N/A" },
      }));
    });
  };

I was able to map through each question since the name is being passed through props is a key inside the actual object, formQuestions[name] . Because i'm mapping through each one I can set that question as a key and return the new state for each question to whatever I would like.

However, if I was to create an onClick={setState('Good')} , React didn't like that and it created an infinite loop. I will look for more solutions and update this post if I find one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM