How to make a select input that is dependent on other inputs to always show a default value in React?

Viewed 206

I have two radio buttons: radio1 and radio2, and one select input. The Select values depend on the radio buttons. I want to set the select value to 1 whenever I select radio1. I've tried setting defaultValue and value to the select input but every time I switch back to radio1 from radio2, the value is always set to 2.

Here's my code, any help is truly appreciated:

import "./styles.css";
import { useState } from "react";

const selectItems = {
  name: "size",
  fields: {
    radio1: [
      {
        value: "1"
      },
      {
        value: "2"
      }
    ],
    radio2: [
      {
        value: "2"
      },
      {
        value: "3"
      },
      {
        value: "4"
      }
    ]
  }
};

const App = () => {
  const [values, setValues] = useState({ radio: "radio1", select: "2" });
  const handleChange = (name, value) => {
    setValues((s) => {
      return { ...s, [name]: value };
    });
  };

  return (
    <div className="App">
      <h2>
        How do I make the Select always be '1' when Radio1 is selected after
        selecting Radio2?
      </h2>
      <input
        type="radio"
        id="radio1"
        value="radio1"
        name="radio"
        onChange={() => handleChange("radio", "radio1")}
      />
      <label htmlFor="radio1">Radio1</label>
      <input
        type="radio"
        id="radio2"
        value="radio2"
        name="radio"
        onChange={() => handleChange("radio", "radio2")}
      />
      <label htmlFor="radio2">Radio2</label>
      <br />
      <select
        id="size"
        name="size"
        onChange={(e) => handleChange("select", e.target.value)}
      >
        {selectItems.fields[values.radio].map(({ value }) => {
          return (
            <option key={value} value={value}>
              {value}
            </option>
          );
        })}
      </select>
    </div>
  );
};

export default App;


example: https://codesandbox.io/s/goofy-danny-p1l3s?file=/src/App.js:0-1460

Edit:

As suggested by some answers, I have tried setting 'selected' as true. In fact, I have tried this before and forgot to mention it on my question. This seem to work, it gives me the desired effect on the browser, but then I get this error on the console:

Warning: Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>.
3 Answers

The main problem here is <option> is taking the same key value. When you are selecting radio2, key becomes 2.Then you are selecting radio1 and for that <select> has <option> with key=2. That is why <select> value not changing. The proof is if you change all <option> values unique, example for radio1 {1, 2} and for radio2 {3, 4, 5} your code works fine.

There may be multiple workarounds but the proper way to solve this is having unique id for each of the <option>.

const selectItems = {
  name: "size",
  fields: {
    radio1: [
      {
        value: "1",
        id: 1
      },
      {
        value: "2",
        id: 2
      }
    ],
    radio2: [
      {
        value: "2",
        id: 3
      },
      {
        value: "3",
        id: 4
      },
      {
        value: "4",
        id: 5
      }
    ]
  }
};
------------------------------------------
<select
        id="size"
        name="size"
        onChange={(e) => handleChange("select", e.target.value)}
      >
        {selectItems.fields[values.radio].map(({ value, id }) => {
          return (
            <option key={id} value={value}>
              {value}
            </option>
          );
        })}
      </select>

Element <option> has property selected that is responsible for determining which item is currently selected. That is the property that will help you to decide which item should be currently selected at any given time. To illustrate this, I have added the following check to your element: <element selected={value === '1'}> and now every time you change the radio from radio1 to radio2 the value changes to 1 as you asked in your question.

My response here is more of a guidance, do not treat as exact step by step instruction as I did not think of any other ways that your program might work or handle different behaviours.

You can define a new state which is called defaultValue. As a result, with setting the value property of select tag by defaultValue, you can achieve your goal:

const App = () => {
  const [values, setValues] = useState({ radio: "radio1", select: "2" });
  const [defaultValue, setDefaultValue] = useState(0);
  const handleChange = (name, value) => {
    setValues((s) => {
      return { ...s, [name]: value };
    });
  };

  useEffect(() => {
    setDefaultValue(selectItems.fields[values.radio][0].value);
  }, [values]);
  return (
    <div className="App">
      <h2>
        How do I make the Select always be '1' when Radio1 is selected after
        selecting Radio2?
      </h2>
      <input
        type="radio"
        id="radio1"
        value="radio1"
        name="radio"
        onChange={() => handleChange("radio", "radio1")}
      />
      <label for="radio1">Radio1</label>
      <input
        type="radio"
        id="radio2"
        value="radio2"
        name="radio"
        onChange={() => handleChange("radio", "radio2")}
      />
      <label for="radio2">Radio2</label>
      <br />
      <select
        id="size"
        name="size"
        value={defaultValue}
        onChange={(e) => handleChange("select", e.target.value)}
      >
        {selectItems.fields[values.radio].map(({ value }, index) => {
          return (
            <option key={value} value={value}>
              {value}
            </option>
          );
        })}
      </select>
    </div>
  );
};

export default App;

Edit laughing-engelbart-ok8jy

Related