0

New to React. I have a NewItem component that should be pretty simple (and I have managed to do similar stuff before without problems): it has a form with two input text fields and it should update a stateful object (I think that's what it's called) when the form is submitted. Yet the state is updated only the second time the user submit the form. Why is that and how can I fix this? (Again, I am aware it's probably a very silly thing to ask, but I have done similar stuff with arrays and thought I got it).

Thank you for your patience and help. Here's the component:

import { useState } from "react";
const NewItem = () => {
  const [newName, setNewName] = useState("");
  const [newType, setNewType] = useState("");
  const [newItem, setNewItem] = useState({ name: "", type: "" });
  
  const getNewName = (event) => {
    const changedName = event.target.value;
    setNewName(changedName);
  };

  const getNewType = (event) => {
    const changedType = event.target.value;
    setNewType(changedType);
  };
  
  const handleSubmit = (event) => {
    event.preventDefault();
    const toAdd = { ...newItem, name: newName, type: newType };
    setNewItem(toAdd);
    console.log(toAdd);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name
        <input type="text" value={newName} onChange={getNewName} />
      </label>
      <label>
        Type
        <input type="text" value={newType} onChange={getNewType} />
      </label>
      <button type="submit">Add</button>
    </form>
  );
};

export default NewItem;
  • Can you please clarify, what exactly is not working as expected? I tried your code in a [sandbox](https://codesandbox.io/s/charming-bush-cdvn8m?file=/src/App.js) and all is fine – Sergey Sosunov Dec 10 '22 at 20:09
  • I checked your code it does change the state on the first submit. Would you please elaborate on the issue more? – Jay F. Dec 10 '22 at 20:33
  • Thanks @SergeySosunov When you console.log the first time you click you get ```{name: "", type: ""}``` so you have to click twice to get the state to update in the intended way. – Bernardino Sassoli de' Bianchi Dec 10 '22 at 20:33
  • (See my comment above) At least that's the behavior I am getting in the browser @JayF – Bernardino Sassoli de' Bianchi Dec 10 '22 at 20:36
  • 1
    Oh, that was the thing? That is a normal behavior, setting a state with setXXX is not updating the actual XXX in place, it will be updated on next render only. – Sergey Sosunov Dec 10 '22 at 20:38
  • 1
    More details [here](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) – Sergey Sosunov Dec 10 '22 at 20:44
  • Yup! Thanks. So I have been dabbling with `useEffect` but I am not sure how I would use it there. Also: why didn't I have that use with a very similar component that updated arrays? Can you point me in the right direction? – Bernardino Sassoli de' Bianchi Dec 10 '22 at 20:50
  • Well with useEffect it is just `useEffect(() => console.log(newItem), [newItem]);` and for an array - I can only guess that you modified the array itself and set it with `setXXX([...arr]);` In same way you can modify `newItem` itself directly and `setNewItem({...newItem})` just after it. And eventually your console.log will work normally in this case. – Sergey Sosunov Dec 10 '22 at 20:57
  • > In same way you can modify newItem itself directly and setNewItem({...newItem}) Isn't that exactly what I am doing? – Bernardino Sassoli de' Bianchi Dec 10 '22 at 22:02
  • 1
    Nope, in `const toAdd = { ...newItem, name: newName, type: newType };` you are constructing a new object having original one unaffected. And if you use `newItem.name = newName; newItem.type = newType; setNewItem({...newItem});` - you will mutate (modify) the existing object, then you will call the setter function and you will pass a newly created object using `Destructuring` – Sergey Sosunov Dec 10 '22 at 22:07

0 Answers0