Jonathan Chiong
Jonathan Chiong

Reputation: 115

React setState not working using event property

const [product, setProduct] = useState({
  productName: "",
  quantity: 0,
  basePrice: 0,
  sellPrice: 0,
})

const handleChange = (e) => {
  let fieldName = e.target.id;
  let fieldValue = e.target.value;
  setProduct({
    fieldName: fieldValue
  });
};

Code above doesnt seem to work. when i log fieldName however, it return productName.

I tried to explicitly use productName instead and its working

const handleChange = (e) => {
  let fieldName = e.target.id;
  let fieldValue = e.target.value;
  setProduct({
    productName: fieldValue
  });
}

Can anyone tell me whats going on under the hood why the initial approach is not working?

PS reason i want to use e.target.id is because there are multiple fields that needs updating Thank you

Upvotes: 2

Views: 201

Answers (2)

teddcp
teddcp

Reputation: 1624

React hooks works differently than the classic setState .

In setState, even if you set the one property and never mention the other properties, those properties will persist. e.g For state of name and email, if you do the setState for name, email value will be there, it won't be erased.

But in useState, the value won't be there. Similar to the previous example, if you set the name property, email will be erased i.e undefined. So either you can spread the old object to get the old values Or you can create separate states for individuals (e.g useState for name and useState for email)

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

export default function App() {
  const [store, setStore] = useState({
    name: "",
    email: ""
  });

  const handleChange = (e) => {
    // console.log(e, e.target.name, e.target.value);
    setStore({...store,  [e.target.name]: e.target.value });   // Spreading
  };

  return (
    <div className="App">
      <label id="name">Name</label>
      <input
        name="name"
        type="text"
        htmlFor="name"
        value={store.name}
        onChange={handleChange}
      ></input>
      <br />
      <br />
      <label id="email">email</label>
      <input
        name="email"
        type="text"
        htmlFor="email"
        value={store.email}
        onChange={handleChange}
      ></input>
    </div>
  );
}

Another way

 const [name, setName] = useState("");
 const [email,setEmail]= useState("");

// handle the change handlers

Upvotes: 1

SiddAjmera
SiddAjmera

Reputation: 39432

The setter on the useState doesn't work like the setState method on a React Class Component.

Setting just a particular field name would override the values of the other fields in the product Object and will set them to undefined.

You'll have to spread the existing product Object to get the values of the other fields and then only override the value of the field by using the [] notation to dynamically set the field name.

Something like this:

setProduct({ 
  ...product,
  [fieldName]: fieldValue 
});

Upvotes: 3

Related Questions