0

I know that in React class components React uses the "this" binding to "track" props and state. In hooks it is achieved thanks to closures, is my doubt?

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

This code works as you would expect a counter, if you were using class component you would have to use setState() in callback mode to access the previous state, but in hooks how does the magic happen?

are there any bindings on the hooks or not?

  • Does this answer your question? [How does JavaScript mechanism behind react hooks work?](https://stackoverflow.com/questions/53895455/how-does-javascript-mechanism-behind-react-hooks-work) – ggorlen Jul 02 '22 at 03:42
  • [React Hooks - What's happening under the hood?](https://stackoverflow.com/questions/53729917/react-hooks-whats-happening-under-the-hood), https://reactjs.org/docs/hooks-faq.html#under-the-hood, https://github.com/zserge/o is also worth reading – ggorlen Jul 02 '22 at 03:45

1 Answers1

0

React keeps track of state by internally counting the number of times useState is called the first time a component mounts. The value passed into useState is then set into React's internal state. For example, given

const Component = () => {
  const [state1, setState1] = useState('one');
  const [state2, setState2] = useState('two');
  return 'foo';
};

React will then have the following state stored internally:

['one', 'two']

with one item in the (hidden, internal) state array for each call of useState that there is.

When a state setter is called, the corresponding item in the internal state array will be updated, and then the component will re-render. When a component re-renders, each useState call then returns the appropriate item in the internal state array. The first useState call will return the first item in the internal state array, the second useState call will return the second item, and so on.

In your code, with hooks, the click handler has a closure over the value of count that existed at that particular render of Counter.

if you were using class component you would have to use setState() in callback mode to access the previous state

Not really - if this code was a class component, it would be free to reference this.state.count directly without using the callback version.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    @ CertainPerformance In your example, in the first render, the array is ['one', 'two]. If you re-render later due to a setState2 call, then the array would look ['one', 'change'] and those values would be taken to the DOM (on return, to my JSX) did I understand correctly? –  Jul 02 '22 at 04:09
  • 2
    Yes, that's how it works – CertainPerformance Jul 02 '22 at 04:09
  • @ CertainPerformance Is the same procedure for props? –  Jul 02 '22 at 04:13
  • 2
    Props are different, they're passed down as arguments, so each time the component re-renders, its body closes over the props for that render. – CertainPerformance Jul 02 '22 at 04:15
  • Ok, so, it's not bindings either? rather that's the magic of closures because in class it is with "this". –  Jul 02 '22 at 04:18
  • @ CertainPerformance "Not really - if this code was a class component, it would be free to reference this.state.count directly without using the callback version.", You mean because the onClick event would capture the value of this.state.count from the render() method, right?Because of that, I don't need callback mode of setState(). –  Jul 02 '22 at 05:31
  • The explanation is pretty similar to https://stackoverflow.com/a/72823446. If your code is such that referencing the value directly will reference the value from the most recent re-render - and you're fine with that (which one often is) - then there's no need to use the callback. – CertainPerformance Jul 02 '22 at 06:08