Closed11

"Keeping Components Pure"を読む

hajimismhajimism

Purity: Components as formulas

関数型プログラミングの文脈においてpure functionとは、この2つの特徴を持った関数である。

  • 自分自身の仕事に専念する。呼び出される前に存在していたオブジェクトや変数を変更することはない。
  • 同じ入力、同じ出力。同じ入力が与えられた場合、純粋関数は常に同じ結果を返すべきである。

React assumes that every component you write is a pure function. This means that React components you write must always return the same JSX given the same inputs:

Reactは、すべてのコンポーネントが純粋な関数であることを前提としている。つまり、same inputに対して常にsame JSXを返して欲しい。

hajimismhajimism

You could think of your components as recipes: if you follow them and don’t introduce new ingredients during the cooking process, you will get the same dish every time. That “dish” is the JSX that the component serves to React to render.

関数というメンタルモデルだからこそ威力を発揮するたとえだなと思う

hajimismhajimism

Side Effects: (un)intended consequences

let guest = 0;

function Cup() {
  // Bad: changing a preexisting variable!
  guest = guest + 1;
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  );
}

↑のサンプルコードで

This means that calling this component multiple times will produce different JSX!

と説明しているが、それはおかしくないか?それだったら、時間によって結果が変わるdata fetchingの結果を返すのもアウトになってしまう。

hajimismhajimism

each component should only “think for itself”, and not attempt to coordinate with or depend upon others during rendering.

コンポーネントがどんな順番でレンダリングされても同じ結果が得られるようにしなくてはいけない。

hajimismhajimism

Detecting impure calculations with StrictMode

impure functionを見つける手立てとして、StrictModeでは2回レンダリングしてますよと

hajimismhajimism

Local mutation: Your component’s little secret

こういうコードもコンポーネントの外でやれば一応大丈夫で、これをlocal mutationと呼んでいるらしい。

  let cups = [];
  for (let i = 1; i <= 12; i++) {
    cups.push(<Cup key={i} guest={i} />);
  }
hajimismhajimism

Where you can cause side effects

These changes—updating the screen, starting an animation, changing the data—are called side effects.

purityの外側で、何か変更を来すときがくる。それを'side effects'と呼んでいる。

Even though event handlers are defined inside your component, they don’t run during rendering! So event handlers don’t need to be pure.

don’t run during rendering なので event handlers don’t need to be pure らしい。重大なヒント。

event handlersが使えないときはuseEffectも使えるけれども、

However, this approach should be your last resort.

らしい。

hajimismhajimism

Why does React care about purity?

  • Your components could run in a different environment—for example, on the server! Since they return the same result for the same inputs, one component can serve many user requests.
  • You can improve performance by skipping rendering components whose inputs have not changed. > - This is safe because pure functions always return the same results, so they are safe to cache.
    If some data changes in the middle of rendering a deep component tree, React can restart rendering without wasting time to finish the outdated render. Purity makes it safe to stop calculating at any time.

ざっくりいうと、

  • 環境に関わらず同じ出力を期待できる。これは同じメンタルモデルでどこでもReactを使えるということで、SSRやRSCの話に繋がっていく。
  • same input, same outputが前提ならば、same inputのときにキャッシュが使える
  • 「最後まで計算してくれないと、次の計算のときに結果が変わる」なんてことが無いはずなので、異なるinputが来たときにはすぐさまそちらの計算に移行すれば良い(?)
hajimismhajimism

Recap

Deepl 翻訳

  • コンポーネントは純粋でなければならない:
    • つまり、自分自身の仕事に専念する。レンダリング前に存在していたオブジェクトや変数を変更してはならない。
    • 同じ入力、同じ出力。同じ入力が与えられた場合、コンポーネントは常に同じJSXを返すべきです。
  • レンダリングはいつでも発生する可能性があるため、コンポーネントは互いのレンダリング順序に依存すべきではありません。
  • コンポーネントがレンダリングに使用する入力を変更すべきではありません。これには、props、state、contextが含まれます。画面を更新するには、既存のオブジェクトを変異させるのではなく、状態を「設定」します。
  • コンポーネントのロジックを、返すJSXで表現するように努めましょう。物事を変更する」必要がある場合、通常はイベント・ハンドラでそれを行う。最後の手段として、Effectを使うこともできる。
  • 純粋な関数を書くには少し練習が必要だが、Reactのパラダイムの力を引き出すことができる。
hajimismhajimism

読んでみて

よく思うけれど、関数型プログラミングにDeep diveすればもっと楽しいだろうか。再度「銀の弾丸」本を読もうか。今でも「お作法」として基本的なところは守れていると思うけれど、もっと精密なメンタルモデルを築きたい気がする。

Reactの教えを守っているおかげで良いコードが書けているのだとしたらありがたい。

purityの裏側にある、effectについても理解を深めたくなった。次はuseEffectかなあ。

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