MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Reactの基礎 - PropsとChildrenのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Reactの基礎 - PropsとChildren
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == Propsは、Reactにおけるコンポーネント間のデータ通信メカニズムである。<br> 親コンポーネントから子コンポーネントへ一方向にデータを渡すことができ、これを <u>単方向データフロー</u> と呼ぶ。<br> <br> Propsには、オブジェクト、配列、関数、文字列や数値等のプリミティブ値といった任意のTypeScript値を渡すことができる。<br> 渡されたPropsは読み取り専用 (イミュータブル) であり、子コンポーネントから直接変更することはできない。<br> <br> 主な特徴は以下の通りである。<br> * 親コンポーネントから子コンポーネントへ一方向にデータが流れる * 任意のTypeScript / JavaScript値 (オブジェクト、配列、関数、プリミティブ) を渡せる * Propsは読み取り専用であり、受け取ったコンポーネントが変更することはできない * 分割代入やデフォルト値の指定により、簡潔に記述できる * TypeScriptと組み合わせることで、型安全なコンポーネント設計が可能になる <br><br> == Propsの基本 == ==== Propsの受け渡し ==== 親コンポーネントは、JSXの属性としてPropsを子コンポーネントへ渡す。<br> データは常に親から子へ一方向に流れる。(単方向データフロー)<br> <br> 以下の例では、<u>Profile</u> コンポーネントが <u>Avatar</u> コンポーネントへ <u>person</u> と <u>size</u> を渡している。<br> <br> <syntaxhighlight lang="typescript"> export default function Profile() { return ( <Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} size={100} /> ); } </syntaxhighlight> <br> <u>オブジェクトは二重中括弧 <code>{{}}</code> で、数値は単一の中括弧 <code>{}</code> で渡す琴に注意する。</u><br> <br> ==== Propsの受け取り ==== 子コンポーネントは、関数の引数として <code>props</code> オブジェクトを受け取る。<br> <br> <syntaxhighlight lang="typescript"> interface AvatarProps { person: { name: string; imageId: string }; size: number; } function Avatar(props: AvatarProps) { let person = props.person; let size = props.size; // person と size を使用する処理 } </syntaxhighlight> <br> この方法では、<u>props.<プロパティ名></u> の形式でアクセスする必要がある。<br> より簡潔に記述するためには、[[#分割代入によるPropsの受け取り 次のセクションで説明する分割代入]]を使用する。<br> <br><br> == 分割代入によるPropsの受け取り == ==== 分割代入の基本 ==== 関数の引数で分割代入を使用すると、Propsを直接変数として受け取ることができる。<br> <br> <syntaxhighlight lang="typescript"> // AvatarProps型は上記で定義済み function Avatar({ person, size }: AvatarProps) { // personとsizeが直接利用可能 } </syntaxhighlight> <br> <u>props.person</u> と記述する代わりに <u>person</u> と直接参照でき、ソースコードが簡潔になる。<br> <br> ==== 残余プロパティ ==== スプレッド構文 <code>...rest</code> を使用すると、指定したProps以外の残りのPropsをまとめて受け取ることができる。<br> <br> <syntaxhighlight lang="typescript"> interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant: string; } function Button({ variant, ...rest }: ButtonProps) { return <button className={variant} {...rest} />; } </syntaxhighlight> <br> * variant *: 取り出して使用するProp *: <br> * ...rest *: variant以外の全てのPropsをオブジェクトとしてまとめたもの *: <u>{...rest}</u> で子要素にそのまま展開して渡すことができる <br><br> == デフォルト値 == ==== 分割代入によるデフォルト値 ==== 分割代入の際に <code>=</code> を使用して、Propが渡されなかった場合のデフォルト値を指定できる。<br> <br> <syntaxhighlight lang="typescript"> interface AvatarProps { person: { name: string; imageId: string }; size?: number; } function Avatar({ person, size = 100 }: AvatarProps) { // sizeが指定されない場合、または undefined の場合、100がデフォルト値として使用される } </syntaxhighlight> <br> デフォルト値が適用される条件と適用されない条件を以下に示す。<br> <br> <center> {| class="wikitable" |+ デフォルト値の適用条件 ! 渡される値 !! デフォルト値の適用 |- | 指定なし (Propが存在しない) || 適用される |- | <code>undefined</code> || 適用される |- | <code>null</code> || 適用されない (nullのまま) |- | <code>0</code> || 適用されない (0のまま) |- | <code>false</code> || 適用されない (falseのまま) |} </center> <br><br> == children == ==== childrenの基本 ==== JSXタグ内にネストされたコンテンツは、自動的に <code>children</code> Propとして子コンポーネントへ渡される。<br> <br> <syntaxhighlight lang="typescript"> interface CardProps { children: React.ReactNode; } function Card({ children }: CardProps) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar /> </Card> ); } </syntaxhighlight> <br> <u>Card</u> コンポーネントは、タグ内にどのような要素が渡されるかを知らなくてもよい。<br> <u>{children}</u> の位置にネストされたコンテンツが展開される。<br> <br> ==== childrenの活用パターン ==== <code>children</code> を活用することにより、汎用的なラッパーコンポーネントを作成できる。<br> <br> * Cardコンポーネントの例 *: <syntaxhighlight lang="typescript"> interface CardProps { children: React.ReactNode; className?: string; } function Card({ children, className }: CardProps) { return ( <div className={`card ${className}`}> {children} </div> ); } </syntaxhighlight> *: <br> * 複数のセクションを持つLayoutコンポーネントの例 *: この場合、<u>sidebar</u> と <u>content</u> のように、Propとして複数のJSX要素を渡す方法も有効である。 *: <syntaxhighlight lang="typescript"> interface LayoutProps { sidebar: React.ReactNode; content: React.ReactNode; } function Layout({ sidebar, content }: LayoutProps) { return ( <div className="layout"> <aside>{sidebar}</aside> <main>{content}</main> </div> ); } <Layout sidebar={<Navigation />} content={<MainContent />} /> </syntaxhighlight> *: <br> * Modalコンポーネントの例 *: <code>isOpen</code> がfalseの場合は、何もレンダリングしない設計にすることで、表示制御を親コンポーネント側で行える。 *: <syntaxhighlight lang="typescript"> interface ModalProps { isOpen: boolean; title: string; children: React.ReactNode; onClose: () => void; } function Modal({ isOpen, title, children, onClose }: ModalProps) { if (!isOpen) return null; return ( <div className="modal-overlay"> <div className="modal"> <h2>{title}</h2> {children} <button onClick={onClose}>Close</button> </div> </div> ); } </syntaxhighlight> <br><br> == スプレッド構文によるPropsの展開 == スプレッド構文を使用すると、Propsをまとめて子コンポーネントへ渡すことができる。<br> <br> 以下の2つの記述は同じ動作をする。<br> <br> <syntaxhighlight lang="typescript"> interface ProfileProps { person: { name: string; imageId: string }; size: number; isSepia: boolean; thickBorder: boolean; } // 冗長な書き方 function Profile({ person, size, isSepia, thickBorder }: ProfileProps) { return ( <Avatar person={person} size={size} isSepia={isSepia} thickBorder={thickBorder} /> ); } // スプレッド構文 (簡潔な記述) function Profile(props: ProfileProps) { return <Avatar {...props} />; } </syntaxhighlight> <br> <u>スプレッド構文は簡潔である一方、どのPropsが渡されるかが不明確になる場合がある。</u><br> <u>そのため、使用は最小限にとどめ、Propsを個別に列挙する方が可読性は高い。</u><br> <br> 全てのコンポーネントでスプレッド構文を使用することは避けること。<br> <br><br> == Props型定義 (TypeScript) == ==== interfaceによるProps型の定義 ==== TypeScriptでは、<code>interface</code> を使用してPropsの型を定義することができる。<br> 型定義により、コンパイル時に型の不一致を検出でき、IDEの補完機能も有効になる。<br> <br> <syntaxhighlight lang="typescript"> interface MyButtonProps { title: string; disabled: boolean; } function MyButton({ title, disabled }: MyButtonProps) { return <button disabled={disabled}>{title}</button>; } </syntaxhighlight> <br> ==== オプショナルPropsと必須Props ==== <code>?</code> を付加することでオプショナル (省略可能) なPropsを定義できる。<br> <code>?</code> のないPropsは必須となり、渡されない場合はコンパイルエラーになる。<br> <br> <syntaxhighlight lang="typescript"> interface CardProps { title: string; // 必須 description?: string; // オプショナル onClick?: () => void; // オプショナルなコールバック } </syntaxhighlight> <br> ==== childrenの型定義 ==== <code>children</code> Propの型には <code>React.ReactNode</code> を使用することが推奨される。<br> <br> <syntaxhighlight lang="typescript"> interface ModalRendererProps { title: string; children: React.ReactNode; } </syntaxhighlight> <br> <code>children</code> の型の選択肢を以下に示す。<br> <br> <center> {| class="wikitable" |+ childrenの型定義 |- ! 型 !! 説明 |- | React.ReactNode(推奨) || 文字列、数値、JSX 要素、null、undefined、配列等全ての値に対応する。<br>最も汎用的であり、通常はこちらを使用する。 |- | React.ReactElement || JSX要素のみを受け付ける、より限定的な型<br>文字列や数値を受け付けないため、必要な場合にのみ使用する。 |} </center> <br> ==== イベントハンドラの型 ==== Reactは各DOMイベントに対応する型を提供している。<br> <br> <syntaxhighlight lang="typescript"> interface InputFieldProps { value: string; onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; } </syntaxhighlight> <br> 代表的なイベントハンドラの型を以下に示す。<br> <br> <center> {| class="wikitable" |+ 代表的なイベントハンドラの型 ! 型 !! 対応するイベント |- | <code>React.ChangeEvent<HTMLInputElement></code> || 入力フィールドの値変更 |- | <code>React.MouseEvent<HTMLButtonElement></code> || ボタンのクリック |- | <code>React.FormEvent<HTMLFormElement></code> || フォームの送信 |- | <code>React.KeyboardEvent<HTMLInputElement></code> || キーボード入力 |- | <code>React.FocusEvent<HTMLInputElement></code> || フォーカスの変更 |} </center> <br><br> == Propsの設計原則 == ==== 単方向データフロー ==== Reactでは、データは親コンポーネントから子コンポーネントへ一方向に流れる。<br> 子コンポーネントが親の状態を直接変更することはできない。<br> <br> 子から親へデータを伝える場合は、コールバック関数をPropsとして渡す方法を使用する。<br> 以下の例では、<u>setFilterText</u> 関数を <u>onFilterTextChange</u> Propとして渡すことで、子コンポーネントが親の状態を更新できる。<br> <br> <syntaxhighlight lang="typescript"> interface SearchBarProps { filterText: string; onFilterTextChange: (text: string) => void; } function Parent() { const [filterText, setFilterText] = useState<string>(''); return ( <SearchBar filterText={filterText} onFilterTextChange={setFilterText} /> ); } function SearchBar({ filterText, onFilterTextChange }: SearchBarProps) { return ( <input value={filterText} onChange={(e) => onFilterTextChange(e.target.value)} /> ); } </syntaxhighlight> <br> この設計パターンにより、状態の変更箇所が明確になり、データの流れを追いやすくなる。<br> <br> Propsの設計における主な原則を以下に示す。<br> <br> <center> {| class="wikitable" |+ Props 設計のベストプラクティス |- ! 項目 !! 説明 |- | データは親から子へ一方向に渡す || 子コンポーネントは受け取ったPropsを直接変更しない。 |- | 子から親への通信はコールバック関数で行う || <code>onChange</code>、<code>onClose</code>、<code>onSubmit</code> 等の命名規則を使用する。 |- | Propsは最小限にする || 不要なPropsを渡さないことで、コンポーネントの責務を明確にする。 |- | TypeScriptで型を定義する || 型定義により、意図しない使用を防ぎ、ソースコードの可読性を高める。 |} </center> <br><br> == 関連情報 == * [[Reactの基礎 - TSXの基本構文]] * [[Reactの基礎 - JSXの基本構文]] * [[Reactの基礎 - 条件レンダリング]] * [[Reactの基礎 - リストレンダリング]] * [[Reactの基礎 - コンポーネント]] <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,Props,children,ReactNode,コンポーネント,単方向データフロー,分割代入,フロントエンド |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の基礎 - PropsとChildren
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse