David
David

Reputation: 17

React select option with multiple object values

I'm trying to save multiple values in one select and saving it in useState to use it again somewhere else. but it's not working I only get undefined values in my console.log .

here is the code:

import * as React from "react";
function App() {
  const [option, setOption] = React.useState({ width: 0, height: 0 });

  const options = [
    {
      label: "first",
      value: { width: 10, height: 10 },
    },
    {
      label: "second",
      value: { width: 20, height: 20 },
    },
    {
      label: "third",
      value: { width: 30, height: 30 },
    },
  ];
  const selectHandler = (e) => {
    setOption(e.target.value);
  };

  console.log(option.width);
  console.log(option.height);

  return (
    <div className="App">
      <h1>Test!</h1>
      <select value={options.value} onChange={selectHandler}>
        {options.map((option) => (
          <option key={option.label}>{option.label}</option>
        ))}
      </select>
      <p></p>
    </div>
  );
}

export default App;

I don't know if it's even possible... thanks in advance!

Upvotes: 0

Views: 3168

Answers (2)

BISWASH BURA
BISWASH BURA

Reputation: 36

You're setting your values in the state in a wrong manner. I've made some changes to your select handler function which hopefully solves your problem:

import * as React from 'react';
function App() {
  const [option, setOption] = React.useState({ width: 0, height: 0 });

  const options = [
    {
      label: 'first',
      value: { width: 10, height: 10 },
    },
    {
      label: 'second',
      value: { width: 20, height: 20 },
    },
    {
      label: 'third',
      value: { width: 30, height: 30 },
    },
  ];
  const selectHandler = (e) => {
    console.log(e.target.value);
    switch (e.target.value) {
      case 'first':
        setOption(options[0].value);
        break;
      case 'second':
        setOption(options[1].value);
        break;
      case 'third':
        setOption(options[2].value);
        break;
    }
  };

  console.log(option.width);
  console.log(option.height);

  return (
    <div className="App">
      <h1>Test!</h1>
      <select value={options.value} onChange={(e) => selectHandler(e)}>
        {options.map((option) => (
          <option key={option.label}>{option.label}</option>
        ))}
      </select>
      <p></p>
    </div>
  );
}

export default App;

Upvotes: 2

Andy
Andy

Reputation: 63514

  1. Add a value attribute to each option. Assign it the option label.

  2. In selectHandler use find to locate the object in the options array with a label that matches the option value, and then add its value property to state.

  3. To log changes to state use useEffect to watch for those changes and then log the result (state updates are async so you wouldn't be able to log the change immediately).

const { useEffect, useState } = React;

function Example({ options }) {

  const [option, setOption] = React.useState({
    width: 0,
    height: 0
  });

  const selectHandler = (e) => {
    const { value } = e.target;
    const found = options.find(obj => obj.label === value);
    if (found) setOption(found.value);
  };

  useEffect(() => console.log(option), [option]);

  return (
    <div className="App">
      <h1>Test!</h1>
      <select onChange={selectHandler}>
        {options.map(option => (
          <option
            key={option.label}
            value={option.label}
            >{option.label}
          </option>
        ))}
      </select>
      <p></p>
    </div>
  );

}

const options=[{label:"first",value:{width:10,height:10}},{label:"second",value:{width:20,height:20}},{label:"third",value:{width:30,height:30}}];

ReactDOM.render(
  <Example options={options } />,
  document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 0

Related Questions