Home > Software engineering >  React Dropdown Custom Component
React Dropdown Custom Component

Time:06-04

I'm trying to create a component to handle a list of any object. But the 'handlechange' event doesn't return the selected item on the list. What is the correct approach?

const DropDownList = (props) => {
const [selected, setSelected] = useState(undefined);
const [list, setList] = useState(props.children ? props.children : []);
const handleChange = (e) => {
    setSelected(e.target.value);
    if (props.setValue) {
        props.setValue(e.target.value);
    }
};
return (
    <div className="col-sm-6">
        <div className="form-group">
            {props.title ? <label>{props.title}</label> : <></>}
            <select className="form-control" value={selected} onChange={handleChange}>
                {list.map((item, k) => (
                    <option key={k} value={item}>{item.label}</option>
                ))}
            </select>
        </div>
    </div>
)

}

One example of list:

   const clima = [
    { label: 'Ensolarado', icon: 'ensolarado' },
    { label: 'Nublado', icon: 'nublado' },
    { label: 'Garoa', icon: 'garoa' },
    { label: 'Chuva Forte', icon: 'chuva_forte' }, ];

const [clima_manha, setClima_Manha] = useState(clima[0])

The use of the component:

<DropDownList value={clima_manha} setValue={setClima_Manha} title="Manhã">{clima}</DropDownList>

CodePudding user response:

Either it is because you use item for value instead of item.label or because you are using setSelected(e.target.value) instead of (setSelected(e)

const DropDownList = (props) => {
const [selected, setSelected] = useState(undefined);
const [list, setList] = useState(props.children ? props.children : []);
const handleChange = (e) => {
    setSelected(e.target.value);
    if (props.setValue) {
        props.setValue(e.target.value);
    }
};
return (
    <div className="col-sm-6">
        <div className="form-group">
            {props.title ? <label>{props.title}</label> : <></>}
            <select className="form-control" value={selected} onChange={handleChange}>
                {list.map((item, k) => (
                    <option key={k} value={item.label}>{item.label}</option>
                ))}
            </select>
        </div>
    </div>
)

CodePudding user response:

I solve this setting the selectedIndex to the outside property.

const handleChange = (e) => {
    setSelected(e.target.value);
    console.log(e)
    if (props.setValue) {
        props.setValue(list[e.target.selectedIndex]);
    }
};

At the list itself, I changed the value to maintain the 'label' of the object.

<select className="form-control" value={selected} onChange={handleChange}>
                {list.map((item, k) => (
                    <option key={k} value={item.label}>{item.label}</option>
                ))}
            </select>

CodePudding user response:

Problem

The value property in option element can only be one of the following:

string | number | string[]

Therefore your item gets called toString method implicitly and all values in option will have the unexpected string value of '[object Object]'. This is why your dropdown value is not changing.

Solution

Since your list item is a JSON, you can do JSON.stringify each item when setting to value and do JSON.parse to get back the JSON from the string.

Try like below.

const clima = [
  { label: "Ensolarado", icon: "ensolarado" },
  { label: "Nublado", icon: "nublado" },
  { label: "Garoa", icon: "garoa" },
  { label: "Chuva Forte", icon: "chuva_forte" }
];

const DropDownList = (props) => {
  const [selected, setSelected] = React.useState(undefined);
  const [list, setList] = React.useState(props.children ? props.children : []);
  const handleChange = (e) => {
    setSelected(e.target.value);
    if (props.setValue) {
      props.setValue(JSON.parse(e.target.value));
    }
  };
  return (
    <div className="col-sm-6">
      <div className="form-group">
        {props.title ? <label>{props.title}</label> : <div/>}
        <select
          className="form-control"
          value={selected}
          onChange={handleChange}
        >
          {list.map((item, k) => (
            <option key={k} value={JSON.stringify(item)}>
              {item.label}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
};

function App() {
  const [clima_manha, setClima_Manha] = React.useState(clima[0]);

  return (
    <div className="App">
      <DropDownList value={clima_manha} setValue={setClima_Manha} title="Manhã">
        {clima}
      </DropDownList>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

NOTE: You can also use an index of the list item to get it done.

  • Related