MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Reactの基礎 - コンポーネントのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Reactの基礎 - コンポーネント
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == Reactにおけるコンポーネントは、UIを構成する独立した再利用可能な部品である。<br> ページ全体を1つの大きなHTML構造として記述するのではなく、ボタン、フォーム、ナビゲーションバー等を個別のコンポーネントとして定義し、それらを組み合わせてアプリケーションを構築する。<br> <br> Reactコンポーネントは本質的にTypeScriptの関数であり、TSX (TypeScript + JSX) を返すことでUIを描画する。<br> React 16.8以降では、Hooks (useState、useEffect等) の登場により、関数コンポーネントがステート管理やライフサイクル処理に対応できるようになり、現在の標準的な記述スタイルとなっている。<br> <br> コンポーネントベースのアーキテクチャには以下に示すメリットがある。<br> <br> <center> {| class="wikitable" |+ コンポーネント分割のメリット |- ! 特性 !! 説明 |- | 再利用性 || 同じコンポーネントを複数の箇所で使い回すことができる。 |- | 保守性 || 変更が必要な場合、対象のコンポーネントのみを修正すればよい。 |- | テスト容易性 || 独立した単位として個別にテストできる。 |- | 関心の分離 || UIのロジックと表示を局所化できる。 |} </center> <br><br> == 関数コンポーネントの定義 == 関数コンポーネントは、TSX (TypeScript + JSX) を返すTypeScript関数として定義する。<br> <br> ==== 基本的な構文 ==== 関数コンポーネントを定義する方法は、function宣言とアロー関数の2種類がある。<br> どちらも同等に機能するため、プロジェクトの慣例に合わせて選択する。<br> <br> * function宣言による定義 *: <syntaxhighlight lang="typescript"> function Profile() { return ( <img src="https://example.com/avatar.jpg" alt="プロフィール画像" /> ); } </syntaxhighlight> *: <br> * アロー関数による定義 *: <syntaxhighlight lang="typescript"> const Profile = () => { return ( <img src="https://example.com/avatar.jpg" alt="プロフィール画像" /> ); }; </syntaxhighlight> <br> ==== TSXを返す ==== コンポーネントは、return文でTSXを返す。<br> <br> TSXの記述方法はシングルラインと複数行の2パターンがある。<br> <br> TSXが単一行に収まる場合は、丸括弧なしで記述できる。<br> <br> <syntaxhighlight lang="typescript"> // 単一行の場合 : 丸括弧は不要 function Avatar() { return <img src="https://example.com/avatar.jpg" alt="アバター" />; } </syntaxhighlight> <br> <u>TSXが複数行にわたる場合は、丸括弧で囲む必要がある。</u><br> <u>丸括弧を省略すると、returnキーワードの後に改行がある場合にTypeScriptが自動的にセミコロンを挿入し、以降のTSXが無視されるため注意が必要である。</u><br> <br> <syntaxhighlight lang="typescript"> // 複数行の場合 : 丸括弧が必須 function UserCard() { return ( <div className="card"> <h2>ユーザ名</h2> <p>自己紹介テキスト</p> </div> ); } </syntaxhighlight> <br> アロー関数では、return文と丸括弧を省略した暗黙returnを使用することもできる。<br> <br> <syntaxhighlight lang="typescript"> // アロー関数の暗黙return const Avatar = () => ( <img src="https://example.com/avatar.jpg" alt="アバター" /> ); </syntaxhighlight> <br><br> == コンポーネントの命名規則 == Reactコンポーネントの命名には、厳守すべき規則が存在する。<br> <br> ==== PascalCase ==== Reactコンポーネントの名前は必ずパスカルケース (PascalCase, 各単語の先頭を大文字にする形式) で記述する。<br> <br> この規則はReactの内部処理と直接関係している。<br> <br> Reactは大文字で始まる識別子をコンポーネントとして扱い、小文字で始まる識別子をHTMLのネイティブタグとして扱う。<br> 例えば、<code><Profile /></code> はReactコンポーネントとして認識されるが、<code><profile /></code> はHTMLタグとして処理される。<br> <br> 下表に、命名例を示す。<br> <br> <center> {| class="wikitable" |+ PascalCase命名の正誤例 ! 命名例 !! 判定 !! 説明 |- | <u>function Profile() {}</u> || 正しい || PascalCaseのため、コンポーネントとして認識される。 |- | <u>function profile() {}</u> || 誤り || 小文字始まりのため、HTMLタグとして認識される。 |- | <u>function UserCard() {}</u> || 正しい || 複数語もPascalCaseで結合する。 |- | <u>function user_card() {}</u> || 誤り || スネークケースは使用しない。 |- | <u><Profile /></u> || 正しい || Reactコンポーネントとして処理される。 |- | <u><profile /></u> || 誤り || HTMLタグとして処理される。 |} </center> <br> ==== ファイル名の慣例 ==== コンポーネントのファイル名は、コンポーネント名と一致させることが慣例である。<br> 例えば、<u>Profile</u> コンポーネントは <u>Profile.tsx</u> というファイルに定義する。<br> <br> ファイルの拡張子はプロジェクトの構成によって異なる。<br> <br> <center> {| class="wikitable" |+ ファイル拡張子の使い分け ! 拡張子 !! 対象プロジェクト !! 用途 |- | <u>.jsx</u> || JavaScriptプロジェクト || JSXを含むReactコンポーネント |- | <u>.tsx</u> || TypeScriptプロジェクト || 型チェック付きのReactコンポーネント |- | <u>.js</u> || JavaScriptプロジェクト || JSXを含まないロジック、ヘルパー関数 |- | <u>.ts</u> || TypeScriptプロジェクト || JSXを含まない型付きロジック、ヘルパー関数 |} </center> <br><br> == ファイル分割 == コンポーネントはファイルに分割して管理することにより、コードの保守性と再利用性が向上する。<br> <br> ==== 1ファイル1コンポーネント ==== 原則として、1つのファイルに1つのコンポーネントを定義する。<br> コンポーネントをファイルに定義したら、exportでエクスポートし、使用する側でimportして利用する。<br> <br> Reactにはdefault exportとnamed exportの2種類のエクスポート方法がある。<br> <br> <syntaxhighlight lang="typescript"> // Profile.tsxファイル // default export: 1ファイルにつき1つだけ使用できる export default function Profile() { return <img src="https://example.com/avatar.jpg" alt="プロフィール" />; } </syntaxhighlight> <br> <syntaxhighlight lang="typescript"> // App.tsxファイル // default exportはimport時に任意の名前を付けられる import ProfileComponent from './Profile'; function App() { return <ProfileComponent />; } </syntaxhighlight> <br> named exportを使用する場合は以下の通りである。<br> <br> <syntaxhighlight lang="typescript"> // components/buttons.tsxファイル interface ButtonProps { label: string; } // named export : 1ファイルに複数定義できる export function PrimaryButton({ label }: ButtonProps) { return <button className="btn-primary">{label}</button>; } export function SecondaryButton({ label }: ButtonProps) { return <button className="btn-secondary">{label}</button>; } </syntaxhighlight> <br> <syntaxhighlight lang="typescript"> // App.tsxファイル // named exportはimport時に波括弧で名前を一致させる必要がある import { PrimaryButton, SecondaryButton } from './components/buttons'; </syntaxhighlight> <br> ==== ディレクトリ構成の例 ==== プロジェクトの規模に応じて、コンポーネントのディレクトリ構成を選択する。<br> <br> * 小規模プロジェクトの場合 *: <u>components</u> ディレクトリにコンポーネントをまとめるシンプルな構成が適している。 *: <syntaxhighlight lang="text"> src/ ├── App.tsx └── components/ ├── Button.tsx ├── Header.tsx └── Profile.tsx </syntaxhighlight> *: <br> * 中大規模プロジェクトの場合 *: 機能別 (feature-based) のディレクトリ構成が保守性を高める。 *: <syntaxhighlight lang="text"> src/ ├── features/ │ ├── user/ │ │ ├── components/ │ │ └── hooks/ │ └── product/ │ ├── components/ │ └── hooks/ └── components/ └── ui/ ├── Button.tsx └── Modal.tsx </syntaxhighlight> <br> コンポーネントにテストファイルやCSSモジュールを伴う場合は、コンポーネントフォルダを作成して関連ファイルをまとめる方法も有効である。<br> <br> components/ └── Button/ ├── Button.tsx ├── Button.test.tsx └── Button.module.css <br> ==== index.tsxによるバレルエクスポート ==== バレルエクスポートとは、<u>index.tsx</u> ファイルを使って複数のエクスポートを1箇所に集約するパターンである。<br> <br> <syntaxhighlight lang="typescript"> // components/index.tsx export { Button } from './Button/Button'; export { Header } from './Header/Header'; export { Profile } from './Profile/Profile'; </syntaxhighlight> <br> バレルエクスポートを使用すると、import文を短縮できる。<br> <br> <syntaxhighlight lang="typescript"> // バレルエクスポートなしの場合 import { Button } from './components/Button/Button'; import { Header } from './components/Header/Header'; // バレルエクスポートありの場合 (短縮される) import { Button, Header } from './components'; </syntaxhighlight> <br> バレルエクスポートを使用する場合は、以下の事柄に注意する。<br> * 円形参照のリスク *: モジュールが相互に参照し合うと循環依存が発生する場合がある。 * バンドルサイズへの影響 *: ツールによっては、不要なコンポーネントもバンドルに含まれる可能性がある。 <br><br> == コンポーネントツリー == Reactアプリケーションは、コンポーネントを階層的に組み合わせたツリー構造として構成される。<br> <br> ==== ツリー構造の考え方 ==== アプリケーションのルートには通常 <code>App</code> コンポーネントが配置され、そこから子コンポーネントが展開される。<br> <br> コンポーネントツリーの例を以下に示す。<br> <br> # コンポーネントツリーの例 App ├── Header │ ├── Logo │ └── Navigation ├── MainContent │ ├── Sidebar │ └── Feed │ └── Post │ ├── Author │ └── CommentList └── Footer <br> <u>重要な注意事項として、コンポーネントの定義は必ずトップレベルで行う必要がある。</u><br> <u>他のコンポーネント関数の内部にコンポーネントを定義することは禁止されている。</u><br> <br> 内部に定義すると、親コンポーネントが再レンダリングされるたびに子コンポーネントが再生成され、パフォーマンスの低下やステート管理のバグの原因となる。<br> <br> <syntaxhighlight lang="typescript"> // 正しい : トップレベルで定義する function Profile() { return <img src="..." />; } function Gallery() { return <Profile />; } // 誤り : コンポーネント内にコンポーネントを定義してはいけない function Gallery() { function Profile() { // この定義は毎回再生成される return <img src="..." />; } return <Profile />; } </syntaxhighlight> <br> ==== コンポーネントの合成 (Composition) ==== Reactではコンポーネントを組み合わせることにより、複雑なUIを構築する。<br> <u>これをコンポーネントの合成 (Composition) と呼ぶ。</u><br> <br> Propsを通じてデータを渡す合成の例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> interface UserCardProps { name: string; avatarUrl: string; } function UserCard({ name, avatarUrl }: UserCardProps) { return ( <div className="card"> <Avatar url={avatarUrl} /> <h2>{name}</h2> </div> ); } function App() { return ( <UserCard name="田中 太郎" avatarUrl="https://example.com/avatar.jpg" /> ); } </syntaxhighlight> <br> childrenパターンを使用すると、JSX要素そのものを子として渡すことができる。<br> <br> <syntaxhighlight lang="typescript"> interface CardProps { children: React.ReactNode; } // Cardコンポーネントはchildrenを受け取る汎用コンテナ function Card({ children }: CardProps) { return <div className="card-wrapper">{children}</div>; } function App() { return ( <Card> <h2>タイトル</h2> <p>任意のコンテンツを渡せる</p> </Card> ); } </syntaxhighlight> <br> 複数の子コンポーネントが同じ状態を共有する必要がある場合は、状態を共通の親コンポーネントに配置する。<br> これを「状態の持ち上げ (Lifting State Up)」と呼ぶ。<br> <br> ==== コンポーネント分割の指針 ==== コンポーネントを適切な粒度で分割することは、保守性の高いソースコードを記述する上で重要である。<br> <br> 下表に、分割を検討すべき状況を示す。<br> <br> <center> {| class="wikitable" |+ コンポーネント分割の判断基準 |- ! 基準 !! 状況 |- | 単一責任の原則 || 1つのコンポーネントが複数の異なる役割を担っている場合 |- | コードの行数 || 1ファイルが150行から200行を超えてきた場合 |- | UIパターンの重複 || 同じUIパターンが複数箇所で使われている場合 |- | テストの複雑化 || コンポーネントのテストが書きにくく、複雑になっている場合 |} </center> <br><br> == 関数コンポーネントとクラスコンポーネント == Reactにはコンポーネントを定義する方法として、関数コンポーネントとクラスコンポーネントの2種類が存在する。<br> <br> ==== 関数コンポーネント ==== 関数コンポーネントはTypeScript関数としてコンポーネントを定義する形式であり、React 16.8以降のHooksの導入により、ステート管理やライフサイクル処理にも対応できるようになった。<br> <br> <u>現在のReact開発における標準的な記述スタイルである。</u><br> <br> 関数コンポーネントの記述例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>カウント: {count}</p> <button onClick={() => setCount(count + 1)}> 増加 </button> </div> ); } </syntaxhighlight> <br> ==== クラスコンポーネント ==== クラスコンポーネントはReact初期から存在するコンポーネントの記述形式である。<br> React 16.8でHooksが導入された以降は、新規開発では関数コンポーネントを使用することが推奨されている。<br> <br> クラスコンポーネントはレガシーコードのメンテナンスや、一部の特殊なユースケース (Error Boundary等) においては引き続き使用される。<br> <br> クラスコンポーネントの記述例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> import React from 'react'; interface CounterProps {} interface CounterState { count: number; } class Counter extends React.Component<CounterProps, CounterState> { constructor(props: CounterProps) { super(props); this.state = { count: 0 }; } render() { return ( <div> <p>カウント: {this.state.count}</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> 増加 </button> </div> ); } } </syntaxhighlight> <br> 下表に、関数コンポーネントとクラスコンポーネントの比較を示す。<br> <br> <center> {| class="wikitable" |+ 関数コンポーネントとクラスコンポーネントの比較 ! 項目 !! 関数コンポーネント !! クラスコンポーネント |- | 構文 || <code>function MyComponent() {}</code> || <code>class MyComponent extends React.Component {}</code> |- | ステート管理 || <code>useState</code> Hook を使用 || <code>this.state</code> を使用 |- | ライフサイクル || <code>useEffect</code> Hook を使用 || <code>componentDidMount</code> 等のメソッドを使用 |- | <code>this</code> の使用 || 不要 || 必要 (バインディングの問題が生じる場合がある) |- | 学習曲線 || 低い || 高い |- | 推奨度 || 推奨 (React 16.8以降の標準) || レガシー・メンテナンス用途 |} </center> <br><br> == 関連情報 == * [[Reactの基礎 - TSXの基本構文]] * [[Reactの基礎 - JSXの基本構文]] * [[Reactの基礎 - 条件レンダリング]] * [[Reactの基礎 - リストレンダリング]] * [[Reactの基礎 - PropsとChildren]] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板,React,JavaScript,TypeScript,TSX,コンポーネント,JSX,関数コンポーネント,クラスコンポーネント,PascalCase,Hooks,useState,useEffect |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Rust]][[カテゴリ:Web]]
Reactの基礎 - コンポーネント
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse