Closed15

useStateのdocsを読む

hajimismhajimism

Overview

useState is a React Hook that lets you add a state variable to your component.

皆さんご存知ですね

hajimismhajimism

Reference

Parameters

関数を渡すときは、Callせずにpureなinitializer functionそのものを渡す

  const [todos, setTodos] = useState(createInitialTodos);
hajimismhajimism

Returns

The set function that lets you update the state to a different value and trigger a re-render.

地味に大事なところ。

hajimismhajimism

Caveats

useState is a Hook, so you can only call it at the top level of your component or your own Hooks.

HookがどうしてTopレベルでしか呼べないのか、useがどうして条件分岐の中でも呼べるのか、しっかり説明できないかも。purityが保たれてればいいって話に行き着く気はするが...。

hajimismhajimism

set functions, like setSomething(nextState)

Parameters

If you pass a function as nextState, it will be treated as an updater function. It must be pure, should take the pending state as its only argument, and should return the next state. React will put your updater function in a queue and re-render your component. During the next render, React will calculate the next state by applying all of the queued updaters to the previous state.

re-renderが引き起こされてから、queueに入ってるupdater functionが計算されるってこと?

hajimismhajimism

Caveats

The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call.

例のあれか?
https://zenn.dev/ikenohi/articles/4a4d659e80237b

If the new value you provide is identical to the current state, as determined by an Object.is comparison, React will skip re-rendering the component and its children.

新しいstate variableが古いそれとObject.isで比較して同じであればre-renderされない

React batches state updates. It updates the screen after all the event handlers have run and have called their set functions. This prevents multiple re-renders during a single event. In the rare case that you need to force React to update the screen earlier, for example to access the DOM, you can use flushSync.

setStateはバッチ処理されるので、逐次re-renderしたいときはflushSyncを使う

hajimismhajimism

Object.jsを確認
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is

console.log(Object.is('1', 1));
// Expected output: false

console.log(Object.is(NaN, NaN));
// Expected output: true

console.log(Object.is(-0, 0));
// Expected output: false

const obj = {};
console.log(Object.is(obj, {}));
// Expected output: false

Object.is() is also not equivalent to the === operator. The only difference between Object.is() and === is in their treatment of signed zeros and NaN values. The === operator (and the == operator) treats the number values -0 and +0 as equal, but treats NaN as not equal to each other.

const isZero = -0 === 0trueconst isNaN = NaN === NaNはfalse
const isZero = Object.is(-0, 0)falseconst isNaN = Object.is(NaN, NaN)はtrue

これを直感的に理解できるような知識がほしい

hajimismhajimism

Usage

Adding state to a component

React will store the next state, render your component again with the new values, and update the UI.

大事なので再確認

hajimismhajimism

Updating state based on the previous state

ありがちなミス

function handleClick() {
  setAge(age + 1); // setAge(42 + 1)
  setAge(age + 1); // setAge(42 + 1)
  setAge(age + 1); // setAge(42 + 1)
}

こうしましょうねと

function handleClick() {
  setAge(a => a + 1); // setAge(42 => 43)
  setAge(a => a + 1); // setAge(43 => 44)
  setAge(a => a + 1); // setAge(44 => 45)
}

React puts your updater functions in a queue.

queueという表現が度々出てくるが、それについてはここに書いてあるらしい。別スクラップにて。
https://react.dev/learn/queueing-a-series-of-state-updates

hajimismhajimism

Is using an updater always preferred?

However, if you do multiple updates within the same event, updaters can be helpful. They’re also helpful if accessing the state variable itself is inconvenient (you might run into this when optimizing re-renders).

If you prefer consistency over slightly more verbose syntax, it’s reasonable to always write an updater if the state you’re setting is calculated from the previous state. If it’s calculated from the previous state of some other state variable, you might want to combine them into one object and use a reducer.

設定する状態が前の状態から計算される場合は、常にアップデータを書くのがreasonableで、それらがパターン化できるならばreducerに押し込もう。

hajimismhajimism

Storing information from previous renders

previous renderingのstate variableを計算に使うために、コンポーネントの中で条件付きsetStateを書くテクがあるらしい。ちょっとこわい。

import { useState } from 'react';

export default function CountLabel({ count }) {
  const [prevCount, setPrevCount] = useState(count);
  const [trend, setTrend] = useState(null);
  if (prevCount !== count) {
    setPrevCount(count);
    setTrend(count > prevCount ? 'increasing' : 'decreasing');
  }
  return (
    <>
      <h1>{count}</h1>
      {trend && <p>The count is {trend}</p>}
    </>
  );
}

Note that if you call a set function while rendering, it must be inside a condition like prevCount !== count, and there must be a call like setPrevCount(count) inside of the condition.

つける条件にも条件がある

This pattern can be hard to understand and is usually best avoided. However, it’s better than updating state in an effect.

むずいから避けたほうがいいけど、useEffectの中でstateを更新するよかマシって書いてある。

hajimismhajimism

読んでみて

数少ない原理原則を意識して説明がされており、かつその原則について多角的に(繰り返し)説明がされているので、とても丁寧なドキュメントだなあと思う。Dan先生が書いたのかな、まじで上手。

どうしてもpureというキーワードが繰り返し出てくるので、1つ上の記事が気になっている。ベースとして各APIのdocsを全部読みたいというのがあるが、次はこれを読む。

このスクラップは2023/07/04にクローズされました