extra functionality of the state hook:
potential performance problem: the intial state is recreated on every render - and only used on the first render
const [foo, setFoo] = useState(
  createObjectWithManyEntries('foo')
);
solution: only do data initialization on the first call - by passing in a function which will only be used on the first render
const [foo, setFoo] = useState(() =>
  createObjectWithManyEntries('foo')
);
basic version for updating state:
setCount(count + 1);
alternative version that may avoid outdated state:
setCount((c) => c + 1);
(see next section)
Sometimes, we may not have direct access to the most recent state entries when computing a new state
particular scenario: asynchronous events in function components (e.g. network requests)
scenarios:
if an event handler function triggers a state setter, the new state is only available after the event handler has finished executing
when an asynchronous action is triggered in a function component, it may keep referencing old state during its execution
example 1:
const [count, setCount] = useState(0);
function incrementTwice() {
  setCount(count + 1);
  setCount(count + 1);
}
this code will set count to 1 twice in a row
example 2:
const [count, setCount] = useState(0);
function increment() {
  setCount(count + 1);
}
function incrementWithDelay() {
  setTimeout(() => setCount(count + 1), 3000);
}
scenario for example 2:
count starts at 0incrementWithDelay is calledincrement is calledincrement is called againincrementWithDelay updates the valuevalues of count: 0 → 1 → 2 → 1
explanation of example 2:
difference of function components and class components when props / state change:
this.props and this.state will be replaced with new objectsnote: in function components, old data may still live on inside older closures
example: buggy code that will keep referencing outdated state in a closure
function Counter() {
  const [count, setCount] = useState(0);
  function startCounting() {
    setInterval(() => {
      // This innermost function will only be created once.
      // The variable "count" will always refer to the
      //   state from the initial rendering (0)
      setCount(count + 1);
    }, 1000);
  }
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => startCounting()}>start</button>
    </div>
  );
}
ESLint rule that can help identifying obsolete data in an effect hook:
react-hooks/exhaustive-deps
(in VS Code, install the ESLint plugin)
possible solutions depending on the scenario (see hints in the linter messages):
possible fix: use a "state transformer function"
change this:
setCount(count + 1);
to this:
setCount((c) => c + 1);
The inner function will always receive the most recent value
possible fix: store data in a ref as well (will be explained in more detail later)
function Counter() {
  const [count, setCount] = useState(0);
  const countRef = useRef(count);
  function startCounting() {
    setInterval(() => {
      countRef.current++;
      setCount(countRef.current);
    }, 1000);
  }
  // ...
}