skip to Main Content

Below is a simple hook

function App() {
  let [counter, setCounter] = useState(0);
  return <button onClick={() => setCounter(counter + 1)}>{counter}</button>;
}

My understanding on how react works is:

React will call App() to get a React element as:

let element = App(); 

and the element can be rendered on the browser, fair enough.

Now I click the button to increment the counter, here is what I don’t understand:

we all know a fucntion’s local variables (counter, setCounter) get destoryed/discarded when the function finishes the execution and get popped out from the stack, so how can setCounter and counter can be accessed again in the callback if those two variables are no longer available?

2

Answers


  1. When the App() function is initially called, the useState(0) call sets up a closure. A closure allows a function to remember the variables in its scope at the time it was created. In this case, it remembers the counter and setCounter variables even after the App() function finishes executing.

    When you click the button and trigger the onClick event, the callback function () => setCounter(counter + 1) is executed. Despite the fact that the App() function has already completed, the callback function retains access to the counter and setCounter variables through the closure.

    Here’s a link for your reference,
    Closures in javascript

    One suggestion is try not to use state in the child component and instead pass the state from parent to child and update the parent component state from child just like in the example from the reference

    Login or Signup to reply.
  2. Your understanding of how React works is mostly correct, but there’s a bit more going on behind the scenes.

    When you call App(), it returns a React element, but it doesn’t directly render the element on the browser. Instead, React takes that element and creates a virtual representation of the DOM (Virtual DOM) based on it. This virtual representation is a lightweight copy of the actual DOM tree that React uses to efficiently compute the changes that need to be made.

    Now, let’s focus on the useState hook in your example. When the component function App() is called, React initializes the counter state variable to 0 and the setCounter function that allows updating the state. These variables are not just regular local variables like you would have in a normal function. Instead, they are part of what we call a "closure."

    A closure is a function along with its lexical environment, which consists of any variables that were in scope when the function was defined. In other words, the function keeps access to the variables that were available in the scope where it was defined, even if that scope has finished executing and the local variables would usually be discarded.

    So when the onClick callback is triggered, it is able to access the setCounter function because it is part of the closure of the App() function. The setCounter function, in turn, has access to the counter variable, which it updates when invoked with a new value.

    In simple terms, you can think of it this way: The App() function creates a closure that captures the counter state variable and the setCounter function. When the button is clicked and the callback is executed, it’s able to access the setCounter function, which, in turn, can access and update the counter variable, thanks to the closure mechanism.

    So, even though the local variables of the App() function would usually be destroyed after the function finishes executing, React’s closure mechanism ensures that the state and updater functions are preserved and accessible when needed. This allows React to maintain and manage stateful data in functional components effectively.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search