TL;DR

  1. UIは状態から一意に決まる
  2. 厳密には「UI = f(props, state, context)」と考えるのが正確
  3. Reactは「state → UI」変換を自動でやる仕組み

はじめに

Reactを調べていると「UI = f(state)」という表現を目にすることがある。
なんとなく理解はしているものの、人に説明できるかと言われると、
真っ直ぐな目で「Yes!!」とは言えないので、改めて文章にして整理する。

f(state) とは

ここでいう f は、state(や props)を受け取って UI を返す計算を指す。

function Counter({ count }: { count: number }) {
  return <span>{count}</span>
}

この関数は、

  • 外部の状態を変更しない
  • 同じ count を渡せば、常に同じ UI を返す

という意味で、純粋な計算

React以前(命令的 UI)

button.addEventListener('click', () => {
  count++
  document.querySelector('#count').textContent = count
  if (count > 10) {
    document.querySelector('#warning').style.display = 'block'
  }
})

この書き方では、次のような問題が起きやすい。

  • 状態とUIが分離していない
    (状態がDOMに分散して保存されている)
  • UIを更新し忘れるとすぐに不整合が起きる
  • 「今どういう状態なのか」をDOMを見ないと判断できない

DOMが表示だけでなく状態の保存場所にもなってしまうのが問題点。

Reactの宣言的UI

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

  return (
    <>
      <span>{count}</span>
      {count > 10 && <Warning />}
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </>
  )
}

このコードでは、

  • UIは常に count の値から計算される
  • 「10を超えたら表示する」は条件として宣言されている
  • 表示・非表示を自分で切り替えていない

結果として、

state が変わるだけで UI は自動的に正しくなる

という状態が実現されている。

厳密には「UI = f(props, state, context)」

実際のReactコンポーネントは、state だけでなく

  • props
  • context

なども入力として受け取る。

そのため、より正確に書くなら次のように表現できる。

UI = f(props, state, context)

Reactはこれらの入力が変わるたびに render を再実行し、
UIを毎回計算し直すことで、表示の整合性を保っている。

まとめ

  • ReactではUIを直接操作しない
  • UIは「現在の状態」から毎回計算される
  • この考え方を一言で表したものが「UI = f(state)」

「DOMをどう更新するか」ではなく、
「この状態ならどう表示されるべきか」を書く。