React公式ドキュメントの自分用メモ

Reactのキャッチアップが必要になったので公式 を一通り読んだことをまとめました。 自分用のメモなので間違い、分かりにくいところがたくさんあると思います。

Hello World

Reactを触る上での最低限のポイント。

  • letconst で変数を定義する(var と等価)
  • クラスメソッドの定義の間にカンマは不要
class MyClass {
  method1() {
    // メソッドの定義
  }
//ここのカンマが不要
  method2() {
    // メソッドの定義
  }
}

比較的新しいJavaScriptの構文

  • メソッド内のthis の値に注意

    • オブジェクト指向の言語ではメソッド内のthisはそのメソッドが属するオブジェクト自体を指すこと
    • JavaScriptではメソッドの呼び出し方によってthis の値が変わることがある
  • アロー関数

    • function よりも短く書ける
    • x => x * 2function(x) { return x * 2; } と同じ
    • 関数内のthis を持たない
    • this は外部メソッドの値を保持する
const obj = {
  name: 'John',
  regularFunction: function() {
    console.log(this.name);
  },
  arrowFunction: () => {
    console.log(this.name);
  }
};

obj.regularFunction(); // 出力: John
obj.arrowFunction();   // 出力: undefined

JSXの導入

JSXについて。

// 丸括弧で囲む
return (
  <div>
    <h1>Hello, World!</h1>
    <p>Welcome to React.</p>
  </div>
);
  • コンパイル後はJavaScriptオブジェクトに変換される
  • if文の条件式、引数などに使える式である
  • 文字列リテラル""''で加工
  • HTMLの属性名はキャメルケース
  • HTMLタグの要素が空の場合は/> で閉じれる
  • 描画前に値はエスケープされる(XSS対策済み)
  • Babelでコンパイルされる
  • JSXをコンパイルしたものをReact要素と呼ぶ
  • React要素を元にDOMを描画する

要素のレンダー

描画に関するDOM関連の基礎知識。

  • DOMとReact要素

    • DOM
      • ブラウザが提供する実際のHTML要素
      • 操作コストが高い
    • React要素
      • Reactが提供する仮想的な要素
      • プレーンなJavaScriptオブジェ区tお
      • 仮想DOM
      • DOMと同様の階層構造を持つ
      • 操作コストが低い
      • React DOMを使用してDOMに変換する
        • DOMとの差分のみを更新する
  • React DOMのルートはid="root"

    • ルートDOMノード
    • SPAはルートDOMノードは1つだけ
  • ReactDOM.createRoot() はルートDOMノードに描画するルートオブジェトを作成する

    • ルートオブジェクトがAPIとしてrender メソッドを用意してくれる
  • React要素はいミューダブル(あとから変更できない)

コンポーネントとprops

React特有のコンポーネント、propsについて。

//関数コンポーネント
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

//クラスコンポーネント
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

stateとライフサイクル

状態管理に関する基礎知識。

  • クラスコンポーネント(class クラス名 extends ...)内のコンストラクタは必ず親クラスのコンストラクタを呼び出す必要がある(super(props);)

  • マウント

    • Reactコンポーネントが初めてDOMに描画されるプロセス
    • コンポーネントの初期化、リソース割り当て、イベント登録などが行われる
    • ライフサイクルの最初のフェーズ
    • マウント時に特定の処理を行うにはcomponentDidMount を使う
  • アンマウント

    • コンポーネントがDOMから削除される時のプロセス
    • リソースの解放、イベント解除などが行われる
    • ライフの最後のフェーズ
    • アンマウント時に特定の処理を行うにはcomponentWillUnmount を使う
  • state は直接変更しない

    • state を変更する場合はsetState() を使う
    • setState はコンストラクタ内で行う
  • state の更新はあいまい
    • 非同期に更新される場合がある
  • setState() は現在のstate に値をマージする

  • props でのデータフローは単一方向

イベント処理

状態を変更する際のイベント処理について。

  • Reactのイベント処理

    • DOM要素のイベント処理と似ている
    • イベント名はキャメルケース
    • JSXのイベントハンドラは文字列ではなく関数を渡す
    • クリックイベントでfalseを返すにはpreventDefault を呼び出す
  • this の値はメソッドがどのオブジェクトに属しているかによって変化する

    • メソッド内でのthis は当メソッドが所属しているオブジェクトを参照する
    • JSX内のthis の扱いには注意する
      • 参照するオブジェクトを明示的にbind する必要がある
  • bind とはthis が参照するオブジェトを指定するための処理

  • コールバック関数をアロー関数で定義することでthis が正しく参照される

    • アロー関数の記述を見つけたらthis の参照先に注意する
  • onClick で呼び出すコールバックメソッドのthis の扱いに注意

    • bindthis の参照先を指定する
    • アロー関数を使いthis の参照先を明示する
  • Reactではクリックイベントが発生すると自動でイベントオブジェクトが自動生成される

  • イベントオブジェクトには次のようなものが含まれている
    • target: イベントが発生した要素
    • type: イベントの種類
    • currentTarget: イベントハンドラがバインドされている要素
  • イベントオブジェクトでユーザーの操作に関する情報を取得できる

条件付きレンダー

render 関連。

リストとkey

リストの描画時の注意点。

  • 要素のリスト項目の作成時には各要素にユニークなキー属性を付ける必要がある
    • 再描画時にリスト要素の一位正を追跡できないため要素の順番を正確に反映できない
    • パフォーマンスの低下
//要素のリスト項目にキーが無い
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

//要素のリスト項目にキーを追加
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
  • 要素のリスト項目のキー要素はユニークな文字列が良い
    • レコードのID
    • ユニークな値
  • リスト形式の子コンポーネントを呼び出す場合は親コンポーネント側でユニークなキーを指定して呼び出す
function ParentComponent() {
  const items = ['item1', 'item2', 'item3'];

  const listItems = items.map((item, index) => (
    <ChildComponent key={item} item={item} />
  ));

  return <ul>{listItems}</ul>;
}

function ChildComponent({ item }) {
  return <li>{item}</li>;
}
  • リスト出力時のmap(){} を使ってインラインで埋め込むこともできる

フォーム

フォーム描画時のポイント。

  • Reactは変更される状態はコンポーネントstate に保持される

    • statesetState() メソッドでのみ更新できる
  • ユーザーが入力した内容、イベントをstate に反映することでコンポーネントを制御する

    • ユーザーの入力をトグルにして動的に色々な処理ができる
    • Rails + Reactで実装するメリット
  • preventDefault() は、通常のブラウザの挙動をキャンセルし、ページ遷移やリロードを防止する

    • ユーザーの入力に対して独自の処理を追加する時に使用する
  • フォーム内のinput タグのvalue属正をstate と同期させることでユーザーの入力をリアルタイムにReact側に送信できる

    • ユーザーの入力がリアルタイムにstate に反映される
  • フォームないのtextarea タグもinput と同様にvalue属性をstate と同期させることでリアルタイムにReact側に送信できる

  • select タグのvalue属性に配列を渡すことでオプションを複数表示することができる

  • [] を使うことでstateの持つプロパティを動的に変得ることができる(jsのComputed Property Names)

    • Rubyのハッシュも同じようなことができる
      • Rubyはキーがシンボルが主流、jsは文字列が主流
this.setState({
  [name]: value
});
  • フォームに入力させたくない場合はvalue属性にundefinedかnullに設定すれば良い
  • フォームに一度入力した後に変更不可にする場合はdisabled 属性をstate を使って動的に変更することで実現できる

state のリフトアップ

state を共通親に設定するリフトアップについて。

  • 複数のコンポーネントstate を共通化したい場合は共通の親コンポーネントstate を移動する(stateのリフトアップ)
  • state のリフトアップの影響
    • 同じような記述(ボイラープレート)がたくさん生まれる
    • バグを発見しやすい
    • コンポーネントstate が共通化される
  • state から計算できる値はstate として保持しない
    • データの一貫性が保たれる
    • データフローが明確になる
    • デバッグ時にデータが追いやすい

コンポジション vs 継承

props を子要素で呼び出す時のポイント。

  • props.children は呼び出し側の子要素を子コンポーネント内で表示できる特別なプロパティ
function Sidebar(props) {
  return (
    <div className="sidebar">
      <h2>{props.title}</h2>
      <p>{props.description}</p>
      <div>{props.children}</div>
    </div>
  );
}

function App() {
  return (
    <Sidebar title="Sidebar Heading" description="This is the sidebar content.">
      <button>Click me</button> // props.childrenで呼び出される
      <p>Additional content</p> // props.childrenで呼ばれる
    </Sidebar>
  );
}

Reactの流儀

描画処理を追加するまでの手順。

UIを作る手順

1. JSONのデータ構造を分割して、それぞれの部分をどのReactコンポーネントとしてUIに表示するか決める(図を書いた方が分かりそう)

  • 表示部分を四角く囲んで名前を付ける
  • 出来上がった図をリスト形式でネストさせて構造を把握する

2. データモデルを受け取りUIの描画だけを行う(ユーザーからの操作は不可)

  • 表示とユーザー操作を切り離す
  • この段階ではprops だけ使い、state は使わない
  • 大きい枠組みから作り始めた方が楽

3. 何をstateにするか決める

  • 必要になった時にstate を元に処理を追加することを意識(不要なstateを作らない)
  • 何をstateにするか決める
    • コンポーネントからのprops であればstate ではない
    • 時間経過で変化しないならstate ではない
    • コンポーネント内のpropsstate から算出できるならstate ではない

4. stateをどのクラスに配置するか決める

  1. stateで表示する全てのコンポーネントを洗い出す
  2. 見つけたコンポーネントの共通の親コンポーネントを見つける
  3. 共通の親コンポーネント or そのさらに親コンポーネント がstateを持つべきか決める
  4. stateを持つべきコンポーネントが見つからなかったらstate保持だけのコンポーネントを作る

感想

React難しい... 今まで学習してきたなかで間違い無く一番難易度が高いと感じてます。 ただ、これを乗り越えれば苦手だったフロントエンドとも仲良くなれそうなので地道にやっていきます!

参照

Hello World – React