1

I have a keeper app where I am adding notes and storing them in database. When I make a post request to the server, I am trying to fetch the _id from database, which will eventually help me to later delete the note ( if needed). Here is my jsx file

function CreateMessage(props) {   

    const [currentGuest, setCurrentGuest] = useState({
        guestName: '',
        guestMessage: '',
        id:''
    });

    function handleMessages(event) {
        const {name, value} = event.target;
        setCurrentGuest(prevGuest => {
            return {
                ...prevGuest,
                [name] : value
            };
        });
    }


    function submitMessage(event) {
    //props.onAdd(currentGuest);
    const params = {
      guestName: currentGuest.guestName,
      guestMessage: currentGuest.guestMessage,
    }
    axios
    .post("http://localhost:8000/notes", params)
    .then(res => {
      console.log("The response is"+res.data._id);
      console.log(res.status);
      setCurrentGuest(prevGuest => {
        console.log(res.data._id)
            return {
                ...prevGuest,
                id: res.data._id
            };
        });
        console.log(currentGuest);
    })

    event.preventDefault();
    }

    return (
    <div>
      <form>
        <input
          name="guestName"
          placeholder="Guest Name"
          value={currentGuest.guestName}
          onChange={handleMessages}
        />
        <textarea
          name="guestMessage"
          placeholder="Write a Message"
          rows="3"
          value={currentGuest.guestMessage}
          onChange={handleMessages}
        />
        <button onClick={submitMessage}>Add</button>
      </form>
    </div>
  );

}

The id is properly being fetched and displayed in ```console.log("The response is"+res.data._id"). But on first submit, the is always empty and stale id gets attached to the currentGuest object on next submit

  • 1
    the code looks like you are passing a function to setCurrentGuest in the .then(), is that intentional? – Donald P Jun 08 '20 at 12:29
  • yes, I m trying to fetch the id from the response and use it to set the id in currentGuest object in setCurrentGuest – Noopur Porwal Jun 08 '20 at 12:38
  • shouldn't setCurrentGuest take an object? – Donald P Jun 08 '20 at 12:44
  • 1
    @DonaldP - Both `setState` and `useState` can also be used in a functional way. We do that when the new state depends on the old state. – Ramesh Reddy Jun 08 '20 at 12:49
  • ah, I learned something new today, thanks! – Donald P Jun 08 '20 at 12:53
  • seems like the posted answer might be correct, on submit you spread the id into state, and on second submit you console.log immediately after calling setState, but I assume at that point in time the state hasn't actually updated yet https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately – Donald P Jun 08 '20 at 13:02

1 Answers1

1
function submitMessage(event) {
//props.onAdd(currentGuest);
const params = {
  guestName: currentGuest.guestName,
  guestMessage: currentGuest.guestMessage,
}
axios
.post("http://localhost:8000/notes", params)
.then(res => {
  console.log("The response is"+res.data._id);
  console.log(res.status);
  setCurrentGuest(prevGuest => {
    console.log(res.data._id)
        return {
            ...prevGuest,
            id: res.data._id
        };
    });
    console.log(currentGuest);
})

event.preventDefault();
}

In the above snippet, after getting the response you're correctly changing the state but the problem is with where you're checking the changed state(console.log(currentGuest)). You're basically logging before the state is changed.

You can use useEffect hook and log the state inside it. This runs every time the currentGuest Changes.

useEffect(() => {
 console.log(currentGuest)
}, [currentGuest])

Update

You can use the modified currentGuest inside the useEffect hook:

useEffect(() => {
  console.log(currentGuest)
  if(currentGuest.id) {
   props.onAdd(currentGuest);
   // You can also reset the state here as follows
   setCurrentGuest({
    guestName: '',
    guestMessage: '',
    id:''
   });
  }
}, [currentGuest]) // You might need to add the necessary dependencies to this array.
Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
  • Thanks @Ramesh. It indeed gives me the updated value, but like you said. But I actually intend to call the commented method `props.onAdd(currentGuest)` when i have the correct id updated in the currentGuest object, and then finally set the currentGuest object to empty again. But if I place it so: ```setCurrentGuest(prevGuest => { return { ...prevGuest, id: res.data._id }}); props.onAdd(currentGuest);}``` It again gets called even before the id is updated. Is there a way we can manage it? Should I put some timeout? – Noopur Porwal Jun 08 '20 at 19:08
  • Basically what if i just not want to console the object value but also run a few lines of codes when i have the updated id in the object? Where should that kind of code be placed – Noopur Porwal Jun 08 '20 at 19:25
  • @NoopurPorwal - That's exactly when you should use the `useEffect` hook. See my updated answer. – Ramesh Reddy Jun 08 '20 at 19:38