Reactjs.org: [Hooks] useState code should include example of setting state with callback.

Created on 4 Dec 2018  ·  6Comments  ·  Source: reactjs/reactjs.org

The documentation for the useState hook could use an example of using a callback to update based on the latest state. This technique exists in the docs for setState(), but not for this hook.

It was not obvious to me that I could pass a callback instead of just a value. Once I guessed that it was possible and tried it, I was able to manage async race conditions more smoothly. But if someone is not familiar with passing a callback to setState, or does not assume that it was included in this new API, they may miss out on the technique. I suggest including this in the Updating State section.

Most helpful comment

It exists in the reference, but that's kinda hard to find (or at least it was to me). I've spent a couple years teaching React, and this is the sort of thing I've had to fix in my own curriculum.

The "functional updates" are, in my opinion, too important to leave to the reference section alone. If you want to make an async change based on previous data, they're vital. That's a pretty common use case. If the purpose of the useState document is to reduce the friction needed to get up and running, then I believe that this belongs.

All 6 comments

It exists in the reference, but that's kinda hard to find (or at least it was to me). I've spent a couple years teaching React, and this is the sort of thing I've had to fix in my own curriculum.

The "functional updates" are, in my opinion, too important to leave to the reference section alone. If you want to make an async change based on previous data, they're vital. That's a pretty common use case. If the purpose of the useState document is to reduce the friction needed to get up and running, then I believe that this belongs.

I agree, it's buried down in the docs despite being a great feature. It's should be on the main page about useState. Before I knew about this feature, I used useRef as a helper to get the state within a closure (which was also recommended somewhere in issues by FB).

I was baffled when I ran into an example of a callback passed to the useState setter hidden on the FAQ page after reading the 'State Hook' page.

IMO, there really shouldn't be a dedicated page if it doesn't explore the entire surface of it's functionality.

There are 2000+ questions for [reactjs] useState console.log on stack overflow. While not sure about the exact proportion, a lot of those tried to debug like this:

   setX(2)
   console.log(x) // why is not updated?!? (ノ°Д°)ノ︵ ┻━┻

While the most popular answer I found is useful and the solution is correct, the explanation provided is not completely accurate:

the state update using the updater provided by useState hook is also asynchronous, and will not immediately reflect and update but will trigger a re-render

The fact that a closure around an (immutable-like) x is not updated has nothing to do with the fact whether or not setX is asynchronous or not.

I got downvoted for my additional explanation about closures in my answer and I couldn't find any useful mention of closures or immutability in the Hooks documentation. So I can give up about closures, if it is too advanced topic...

But I don't believe it is responsible if we let people use Hooks while they don't understand the core concept behind using const on the line const [x, setX] = useState() - it seems to me that too many people just miss the point.

Can we add an EARLY explanation that the first value returned by useState should be treated as immutable?

Also, the first example in both https://reactjs.org/docs/hooks-intro.html and https://reactjs.org/docs/hooks-state.html provides a wrong model about how Hooks work, as if setCount(count + 1) will work in _other situations™_ too.

I propose alternative first examples, e.g. e-shop like count of items:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(1);

  return (
    <div>
      <p>Current count is: {count}</p>
      <button onClick={() => setCount(0)}>Zero</button>
      <button onClick={() => setCount(currentCount => currentCount + 1}>+</button>
      <button onClick={() => setCount(currentCount => currentCount - 1}>-</button>
    </div>
  );
}

or a simpler quiz answer options (avoiding functional updates):

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "option"
  const [option, setOption] = useState('undecided');

  return (
    <div>
      <p>Selected option: {option}</p>
      <button onClick={() => setOption('A')}>A</button>
      <button onClick={() => setOption('B')}>B</button>
    </div>
  );
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

gaearon picture gaearon  ·  4Comments

andresmatasuarez picture andresmatasuarez  ·  5Comments

ahtee picture ahtee  ·  4Comments

gaearon picture gaearon  ·  6Comments

VinayakBagaria picture VinayakBagaria  ·  3Comments