How to get the value of selected option from React hooks?

Viewed 6458

I have this React Component like below:

const ProductCell = (props) => {
    const [option, setOption] = useState();

    return(
     <div>
        <NativeSelect
            value={option}
            onChange={e => setOption(e.target.value)}
        >

            {props.product.variations.nodes.map(  // here I extracted all the item
                (item, i) => (
                    <option value={item} key={i}>{item.name}</option>  // set option value to item object
                ))
            }
                    
        </NativeSelect>

        <Typography variant="h5" className={classes.title}>
            {option.price}  // I want to update the value of price according to the selected option. 
        </Typography>       // according to the selected option above
     </div>
    )
}

I have a NativeSelect component which is from React Material-Ui, so basically it is a Select html tag. In the code above, what I do is, extract all the element inside props.product.variations.nodes and put all the extracted item and put each of the element into a <options/> tag.

The Json object for item will look like this:

"variations": {
    "nodes": [
        {
            "id": "someId",
            "name": "abc1234",
            "variationId": 24,
            "price": "$100.00"
        },
        {
           .. another ID, name,variation and price
        }
    ]
}

As you can see, I targeting the part of id, name , variationId and price as an object. Therefore each <option/> tag will present with item.name as the presentation to user. So far in this part having no problem, let say having 5 variations, and can present all of them.

What I want to do is:

I want to update the value of price under the <Typography /> component. Example, user selected 3rd options in the Select, I want to update the price value of the 3rd item in <Typography /> .

What I tried:

I create a react hooks const [option, setOption] = useState(); , then when handleChange, I setOption() with event.target.value in NativeSelect component . Therefore the value of <option /> tag is set as item object.

Lastly, I get the price value from the hooks in the Typography section.

But what I get is:

The price value is undefined in console log. So I can't get the value of option.price.

and this error:

TypeError: Cannot read property 'price' of undefined

Question:

How can I get the option.price value(which I expect it is same with item.price) outside the NativeSelect component in my above example?

I tried my best to explain based on what I understand by this time being. So any help will be well appreciated.

Update:

Here is what I got when console log the item object in variation.node.map() section and data object inside onHandleChanged section, but also produce the same result:

enter image description here

1 Answers

You have to set a default selected option on your ProductCell component. Also your onChange handler will receive a string instead of an object when you access the value on event.target.value.

From the docs

function(event: object) => void event: The event source of the callback. You can pull out the new value by accessing event.target.value (string).

event.target.value will be a string even though you pass the value as object on NativeSelect component.

What you might want to do? Don't set the current selected item as an object, instead use the id and have a function that look-ups the item using the current selected id.

Check the code below.

const ProductCell = (props) => {
  const { variations } = props.product;
  const { nodes } = variations;

  // we're setting the first node's id as selected value
  const [selectedId, setSelectedId] = useState(nodes[0].id);

  const getSelectedPrice = () => {
    // finds the node from the current `selectedId`
    // and returns `price`
    const obj = nodes.find((node) => node.id === selectedId);
    return obj.price;
  };

  function onChange(event) {
    // event.target.value will be the id of the current
    // selected node
    setSelectedId(parseInt(event.target.value));
  }

  return (
    <div>
      <NativeSelect value={selectedId} onChange={onChange}>
        {nodes.map((item, i) => (
          <option value={item.id} key={i}>
            {item.name}
          </option>
        ))}
      </NativeSelect>
      <Typography variant="h5">{getSelectedPrice()}</Typography>
    </div>
  );
};

Also notice that were passing the id as a value prop on each of our options.

<option value={item.id} key={i}>

And how we now display the price, we're calling our getSelectedPrice().

Edit gallant-agnesi-289ei


Update

I thought a better solution. I realized that you can set your selected state as an object and on your onChange handler given the id from event.target.value find the item on nodes and set that as your new selected state.

const ProductCell = (props) => {
  const { variations } = props.product;
  const { nodes } = variations;

  const [selected, setSelected] = useState(nodes[0]);

  function onChange(event) {
    const value = parseInt(event.target.value);
    setSelected(nodes.find((node) => node.id === value));
  }

  return (
    <div>
      <NativeSelect value={selected.id} onChange={onChange}>
        {nodes.map((item, i) => (
          <option value={item.id} key={i}>
            {item.name}
          </option>
        ))}
      </NativeSelect>
      <Typography variant="h5">{selected.price}</Typography>
    </div>
  );
};

Edit quizzical-nash-mg4bc

Related