をみて、疑問に感じたことに対するメモ
Reactでコンポーネントを呼び出す方法には2種類ある。<Component />とComponent()だ。見た目は似ているが、Reactの内部では全く異なる扱いを受ける。今回、この違いについてZennの記事を読んで学習した際に疑問がでてきたのでその部分をまとめる。
コンポーネント関数呼び出しの違い
コンポーネント呼び出し
- Appが再レンダリング → 新しいCounter関数が作られる
- Reactは前回と異なる関数 = 別のコンポーネントと認識
- 古いCounterをアンマウント → 新しいCounterをマウント
- SlowMountもアンマウント・マウントされるため、重い初回処理が毎回走る
関数呼び出し Counter()の場合:
- Appが再レンダリング → 新しいCounter関数が作られる
- しかしCounter()はただの関数実行なので、Reactは関与しない
- 返り値のJSX(
)が親に展開される - SlowMountはファイルのトップレベルで定義されているため、Appの再レンダリングでも再生成されない
- Reactは「前回と同じSlowMountコンポーネント」と認識
- → 再レンダリングのみで、アンマウント・マウントは起きない
核心部分
<Component />(コンポーネント呼び出し):Reactがライフサイクルを管理するComponent()(関数呼び出し):Reactはライフサイクルを管理しない
なぜライフサイクルの有無が生まれるのか
- コンポーネント呼び出しは
jsx()関数を経由してReact要素を生成 - Reactはこのオブジェクトをもとにライフサイクルを管理
- 関数呼び出しはReact要素を経由しないため、Reactの管理外
コンポーネント内でコンポーネントを定義する問題
render hooksパターン
const useChecks = (labels) => { const [checkList, setCheckList] = useState(...); const isAllChecked = checkList.every(x => x); const renderChecks = () => <Checks checkList={checkList} />; return [isAllChecked, renderChecks]; }; const App = () => { const [isAllChecked, renderChecks] = useChecks(labels); return ( <> {renderChecks()} {/* 関数呼び出し */} <button disabled={!isAllChecked}>次へ</button> </> ); };
- カスタムフックから
renderComponent()のような関数を返す - 状態管理とUIをセットでカプセル化
- 親には計算結果など必要な情報だけ公開
- 使う場面は限定的だが、責務分離に有効
実務での使い分け
- 基本は
<Component />を使う Component()はrender hooksパターンなど特殊なケースのみ
参考:
- Reactにおける