🐙

[初心者向]Reactスターターはここから始めろ!その1

2024/10/30に公開

前提

当記事はJavaScriptもReactもそんなに詳しくないよって人向けです。

React公式のクイックスタートを終わらせていること(Reactのをなんとなく理解している状態)
↓↓前記事↓↓
https://zenn.dev/kkyoka/articles/ebc370c9b2a4c3
https://zenn.dev/kkyoka/articles/127b8e6ef2b798
その上で公式ドキュメントの「Reactを学ぶ」を読んでいきます📖
以下はそのまとめのその1

Reactの仕組みに関すること

基本

  • Reactはインタラクティビティ・ファースト
    • 従来の、「HTMLでコンテンツをマークアップした上にJavaScriptで動きを加える」みたいなものではなく、「JavaScript主体で、それに対してマークアップを添えることができるよ🙆‍♀️」ということ
  • ほとんどのコードベースでJSXが使われている
    • JSXとは:JavaScript の拡張であり、JavaScriptファイル内にHTMLのようなマークアップを書けるようにした構文拡張
  • 制御フロー(条件分岐など)はJavaScriptで処理される
    • Reactではテンプレートや独自の構文を使うのではなく、JavaScriptそのものを使って条件分岐やループを記述する
    • 独自のものではないから書きやすいし身につけたスキルも汎用的に使えるね👍
  • クライアントに送信するために必要なJavaScriptをすべてひとつにまとめるビルドステップが必要(その作業をバンドラが担う)

propsについて

propsとは:コンポーネントの引数

  • props はイミュータブル (immutable)であるべき
    • propsはコンポーネント内で更新するのではなく、親コンポーネントに新しいpropsを渡してもらうようにする
    • 古い使われなくなったpropsはJavaScriptのガベージコレクションによって自動で廃棄される

純関数について

純関数とは:同じ入力に対して常に同じ結果を返し、副作用を持たない関数のこと

  • コンポーネントは常に純関数である前提に設計されている
  • 他コンポーネントに依存しない形に実装する必要がある
    • // 不純な書き方
      function Cup() {
          // guestの値をここで変更しているため、呼びだすタイミングによって表示される値が異なる
          guest = guest + 1;
          return <h2>Tea cup for guest #{guest}</h2>;
        }
      
  • 純関数で得られるメリット
    • どこで実行しても同じ動作をするように作られているため、コンポーネントが異なる環境でも実行できるようになる
      • 外部状態や副作用に影響されないため、コンポーネントが多数のユーザリクエストを処理できる
    • いつも同じ結果を返すようにしている前提があるため安全にキャッシュできる
      • 入力値が変化しない場合、レンダーをスキップすることができる
    • レンダーの途中でデータが変化した場合でもすぐに新しいレンダーを開始できる
      • 処理を途中で中断することによる弊害がないため、すぐに新しい処理を開始できる

ツリー構造について

  • レンダーツリー
    • コンポーネントのネストの関係性を図化したもの
  • モジュール依存関係ツリー
    • アプリのモジュールの依存関係を図化したもの(どこで何が何をimportしているのか?がわかる)
    • バンドラは依存関係ツリーをもといバンドル対象を決めるが、バンドルサイズが大きいと遅延に繋がる
      • 依存関係ツリーを把握して、問題を回避しよう

書き方について

Reactに関すること

  • 関数は大文字から始める
  • returnが複数行にまたがるときは()で囲む
    • // 1行の場合
      function Hoge() {
          return <div>何かしら</div>
      }
      // 複数行の場合
      function Hoge() {
          return (
              <>
                  <div>ああ</div>
                  <div>いい</div>
              </>
          )
      }
      
  • エクスポートは名前付きエクスポートデフォルトエクスポートも可能。ひとつのファイルでどちらもエクスポートすることができる。
    • 同様に、どちらもインポート可能
      • デフォルトエクスポートをインポートするとき:import Hoge from './Hoge.js';
      • 名前付きエクスポートをインポートするとき:import { Fuge } from './Hoge.js';
  • propsについて
    • 分割導入
      • propsで受け取るのではなく{ person, size }のように分割した状態で受け取ること
      • function Avatar({ person, size }) {
            // ...
        }
        
      • propsの初期値はfunction Avatar({ person, size = 100 }){}のような書き方で設定できる
      • ただし初期値が使われるのはundefinedを渡した場合にのみでnull0を渡した場合にはデフォルト値は使われない
    • スプレッド構文
      • 子コンポーネントに、propsの各要素の名前を列挙することなくすべて受け渡すことができる
      • function Profile(props) {
            return (
                <div className="card">
                    <Avatar {...props} /> // ここでそのまま渡している
                </div>
            );
        }
        
    • コンポーネントの受け渡し
      • propsにはコンポーネントも渡せる
      • // コンポーネントの定義
        function Card({ children }) {
            return (
              <div className="card">
                {children}
              </div>
            );
        }
        // Cardに<Avatar />というコンポーネントをpropsとして渡している
        export default function Profile() {
            return (
                <Card>
                    <Avatar />
                </Card>
            );
        }
        
  • false,null,undefinedの場合は何も表示されない
    • function Card({ children }) {
          return null; // nullを返す
      }
      // Cardに<Avatar />というコンポーネントをpropsとして渡している
      export default function Profile() {
          return (
              <Card></Card> // 何も表示されない
          );
      }
      
  • <React.StrictMode>を使って、二回呼び出しても結果が変わらない状態を担保できる
    • 開発中に限り、各コンポーネント関数を2回呼び出ししてくれるので、純関数になっていないコンポーネントを見つけるのに役立つ
  • コンポーネントをネストして使用するのはOK,でもネストして定義するのはNG
    • // NG例
      export default function Gallery() {
          // Galleryコンポーネントの中でProfileコンポーネントの定義をするのはNG
          function Profile() {
            // ...
          }
          // ...
      }
      
  • リストアイテムにはkeyが必要
    • Reactが適切にDOM操作する際に、要素を一意に特定できるようにしておく必要がある

JavaScriptに関すること

  • JavaScript の && 式 が便利
    • JavaScriptではfalse==0だけど{0 && <div>hoge</div>}0とみなされるので注意
  • アロー関数は、{}を省略しない場合はreturnを明示的に書く必要があるので注意
    • // returnが不要 
      const func = (x) => x * x; // 暗黙のreturnがある
      
      // returnが必要
      const func2 = (x, y) => {
          return x + y;
      };
      

JSXに関すること

  • HTMLをJSX構文に変換する用のコンバータがある
  • JSX内でJavaScriptの変数を使用する際は{}で囲む
    • JavaScriptでオブジェクトを定義する際は{ hoge:xxxx, fuge:yyy }と書くので、オブジェクトをJSX内で使う場合は{{ hoge: xxxx, fuge: yyy }}と書く(波括弧が2つある場合はオブジェクトを表してるんだな〜と捉えよう)
  • コンポーネントから複数の要素を返すには、それを単一の親タグで囲む必要がある
    • JavaScriptの関数で複数のオブジェクトをreturnしたいときに配列化しないといけないのと同じ
  • 基本はキャメルケースで書く必要があるが、aria-*data-*属性はHTML属性と同じようにハイフン付きで書く必要がある
  • インラインのstyle属性はキャメルケースで書く必要がある
    • <ul style="background-color: black">としたい場合、<ul style={{ backgroundColor: 'black' }}>と書く

感想

「制御フロー(条件分岐など)はJavaScriptで処理される」って箇所、最初はJavaScriptのライブラリだから当たり前では?と思ったのだけど、
今現場で使っているTwigというテンプレートエンジンはTwig独自の書き方で制御していて、それに比較すると「なるほど、その辺もJavaScriptで書けるのは良い👍」となった

参考

Discussion