Home > Software design >  Navigating through different pages with onClick & radio buttons - React.js
Navigating through different pages with onClick & radio buttons - React.js

Time:03-05

*Using react-router-dom and react.js

I have two different set of radio buttons. One set has 2 buttons while the other set has 3. I want to navigate to a new page whenever a user clicks on two buttons (one in each set). We have a total of six different outcomes, therefore 6 different pages to navigate to. It seems to work fine but with one problem: it only works when we click on a button for a second time. Example: Clicking on "Messages" & "Global" doesn't work initially and doesn't do anything but then if we click on a different button, then it navigates to the initial set of buttons we clicked.

Does anyone know how to fix this issue? Thank you.

import { useNavigate } from 'react-router-dom';

export default function DisplayHomeOptions() {
    let navigate = useNavigate();
    const [formData, setFormData] = React.useState({ location: "", selector: "" })

    function handleChange(event) {
        const { name, value, type, checked } = event.target
        setFormData(prevFormData => {
            return {
                ...prevFormData,
                [name]: type === "checkbox" ? checked : value
            }
        })
    }

    function test() {
        return (
            formData.location === "National" && formData.selector === "Polls" ? navigate("/np") :
                formData.location === "Global" && formData.selector === "Questions" ? navigate("/gq") :
                    formData.location === "Global" && formData.selector === "Polls" ? navigate("/gp") :
                        formData.location === "National" && formData.selector === "Messages" ? navigate("/nm") :
                            formData.location === "National" && formData.selector === "Questions" ? navigate("/nq") :
                                formData.location === "Global" && formData.selector === "Messages" ? navigate("/gm") : null
        )
    }


    return (
        <div>
            <fieldset>
                <legend>Option #1</legend>
                <input
                    type="radio"
                    name="location"
                    value="Global"
                    onChange={handleChange}
                    onClick={test}
                />

                <label htmlFor="Global">Global</label>
                <input
                    type="radio"
                    name="location"
                    value="National"
                    onChange={handleChange}
                    onClick={test}
                />
                <label htmlFor="National">National</label>
            </fieldset>

            <fieldset>
                <legend>Option #2</legend>
                <input
                    type="radio"
                    name="selector"
                    value="Messages"
                    onChange={handleChange}
                    onClick={test}


                />
                <label htmlFor="Messages">Messages</label>
                <input
                    type="radio"
                    name="selector"
                    value="Questions"
                    onChange={handleChange}
                    onClick={test}

                />
                <label htmlFor="Questions">Questions</label>
                <input
                    type="radio"
                    name="selector"
                    value="Polls"
                    onChange={handleChange}
                    onClick={test}
                />
                <label htmlFor="Polls">Polls</label>
            </fieldset>
        </div>
    )
}```

CodePudding user response:

Issue

The issue is that React state updates aren't immediately processed, they are enqueued and asynchronously processed later. The formData state update from handleChange is not yet available when test function is called as the same time.

Solution

It seems you want the act of navigation to be an effect of selecting from the radio buttons. Move the test function logic into an useEffect hook to issue the imperative navigation.

Example:

export default function DisplayHomeOptions() {
  const navigate = useNavigate();

  const [formData, setFormData] = React.useState({
    location: "",
    selector: ""
  });

  useEffect(() => {
    const { location, selector } = formData;
    switch (true) {
      case location === "National" && selector === "Polls":
        navigate("/np");
        break;

      case location === "Global" && selector === "Questions":
        navigate("/gq");
        break;

      case location === "Global" && selector === "Polls":
        navigate("/gp");
        break;

      case location === "National" && selector === "Messages":
        navigate("/nm");
        break;

      case location === "National" && selector === "Questions":
        navigate("/nq");
        break;

      case location === "Global" && selector === "Messages":
        navigate("/gm");
        break;

      default:
      // ignore
    }
  }, [formData]);

  function handleChange(event) {
    const { name, value, type, checked } = event.target;
    setFormData((prevFormData) => {
      return {
        ...prevFormData,
        [name]: type === "checkbox" ? checked : value
      };
    });
  }

  return (
    <div>
      <fieldset>
        <legend>Option #1</legend>
        <input
          type="radio"
          name="location"
          value="Global"
          onChange={handleChange}
        />

        <label htmlFor="Global">Global</label>
        <input
          type="radio"
          name="location"
          value="National"
          onChange={handleChange}
        />
        <label htmlFor="National">National</label>
      </fieldset>

      <fieldset>
        <legend>Option #2</legend>
        <input
          type="radio"
          name="selector"
          value="Messages"
          onChange={handleChange}
        />
        <label htmlFor="Messages">Messages</label>
        <input
          type="radio"
          name="selector"
          value="Questions"
          onChange={handleChange}
        />
        <label htmlFor="Questions">Questions</label>
        <input
          type="radio"
          name="selector"
          value="Polls"
          onChange={handleChange}
        />
        <label htmlFor="Polls">Polls</label>
      </fieldset>
    </div>
  );
}

An optimization may be to declare a Map of target paths from the location and selector values as keys.

const navTarget = {
  National: {
    Messages: "/nm",
    Polls: "/np",
    Questions: "/nq",
  },
  Global: {
    Messages: "/gm",
    Polls: "/gp",
    Questions: "/gq",
  }
}

...

useEffect(() => {
  const { location, selector } = formData;
  if (location && selector) {
    const target = navTarget[location][selector];
    if (target) {
      navigate(target);
    }
  }
}, [formData]);

CodePudding user response:

onClick event fires before onChange event. To account for this, you could move navigation into the onChange event handler.

  • Related