Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is React state not updated inside functions? [duplicate]

I have a component that renders a table with objects. This component shows a button that, when pressed, sends the parent a specific object. The parent must set it in the state to display some graphical stuff. The rendering is working correctly, what I don't understand is why I am getting an outdated value after setting the state correctly. It's not a race condition, React is simply ignoring the updated value of a variable, even when it re-renders the component correctly.

A minimal example:

import { useState } from "react";
import { SomeComponent } from "./SomeComponent";

export default function App() {
  const [currentID, setCurrentID] = useState(null);

  function getData() {
    console.log("Getting data of: ", currentID); // PROBLEM: this is null
  }

  function setAndRetrieveData(value) {
    setCurrentID(value);

    // Just to show the problem and discard race conditions.
    setTimeout(() => {
      getData();
    }, 1500);
  }

  return (
    <div className="App">
      <h1>Current ID: {currentID}</h1> {/* This works fine */}
      <SomeComponent getInfoFor={setAndRetrieveData} />
    </div>
  );
}

SomeComponent:

export function SomeComponent(props) {
  const randomID = 45;

  return <button onClick={() => props.getInfoFor(randomID)}>Get info</button>;
}

Edit react update state

Even with solutions like useStateCallback the problem persists.

Is there a way to do this without having to use the awful useEffect which is not clear when reading the code? Because the logic of the system is "when this button is pressed, make a request to obtain the information", using the hook useEffect the logic becomes "when the value of currentID changes make a request", if at some point I want to change the state of that variable and perform another action that is not to obtain the data from the server then I will be in trouble.

Thanks in advance

like image 482
Genarito Avatar asked Jun 24 '26 01:06

Genarito


1 Answers

I think this is an issue with the way Javascript closures work.

When you execute a function, it gets bundled with all the data that pertains to it and then gets executed.

The issue is that you call this:

setTimeout(() => {
      getData();
    }, 1500);

inside setAndRetrieveData(value).

Even though it's inside a setTimeout, the getData() function has been bundled with the information it needs (currentID) at that point in time, not when it actually runs. So it gets bundled with the currentId before the state update takes place

Unfortunately, I would recommend using useEffect. This is the best way to ensure you avoid issues like this and any potential race conditions. Hopefully someone else can provide a different approach!

like image 101
Pelayo Martinez Avatar answered Jun 26 '26 14:06

Pelayo Martinez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!