今回は他のコンポーネントに対して値を渡す方法、propsについて学習していきます。
同じコンポーネントを色違いで使いたい
第五回で作成したListコンポーネントを、色違いで2つ並べたいとします。
このためにList1.tsxとList2.tsxを作ってコピペするのは、さすがに非効率です。そこで登場するのがpropsです。外から値を渡して内部で使えるようにすると、コンポーネントを簡単に使い回せるようになります。
まずは色のクラスをGreet.cssに追加しておきましょう。
/* Greet.css に追記 */
.red { color: red; }
.blue { color: blue; }
.green { color: green; }
propsの受け取り方
コンポーネントの引数にpropsを定義します。
//List.tsx
type ListProps = {
color?: string;
}
const List = (props: ListProps)=> {
console.log(props);
return (
<ul className="item-list">
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
</ul>
);
}
export default List;
TSXで書いているので、引数には型が必要です。typeでListPropsという型を宣言し、引数の後ろに: ListPropsと付けています。プロパティ名の後ろの?は「渡さなくてもよい」という意味です。
渡す側は、HTMLの属性と同じ書き方です。
//Greet.tsx
import "./Greet.css"
import List from "./List"
const Greet = ()=> {
return (
<div className="component">
<h3>Hello World</h3>
<List color="red" />
</div>
);
}
export default Greet;
コンソールを確認すると{ color: "red" }と表示されます。colorという属性名でredという値を設定すると、propsオブジェクトのcolorプロパティにredが入って渡ってきます。
型に無い属性を渡すとその場でエディタが教えてくれるので、そこはTSXの利点です。
渡した値を使ってみる
受け取った値をクラス名に使って、色を変えてみましょう。classNameを式にして、バッククォートで組み立てます。
//List.tsx
type ListProps = {
color?: string;
}
const List = (props: ListProps)=> {
return (
<ul className={`item-list ${props.color}`}>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
</ul>
);
}
export default List;
classNameがitem-list redになり、リストの文字が赤くなりました。
渡す値を変えるだけで見た目が変わるので、同じコンポーネントを使い回せます。
//Greet.tsx
import "./Greet.css"
import List from "./List"
const Greet = ()=> {
return (
<div className="component">
<h3>Hello World</h3>
<List color="blue" />
<List color="red" />
</div>
);
}
export default Greet;
青と赤のリストが2つ並びました。
propsという名前は慣習
ここからは少しTypeScriptの話になります。
引数名のpropsは慣習的にそう書いているだけで、pなどでも問題なく動きます。
//List.tsx
const List = (p: ListProps)=> {
return (
<ul className={`item-list ${p.color}`}>
...
</ul>
);
}
文法的にはどちらでも同じ意味です。ただ読み手が混乱するので、素直にpropsにしておきましょう。
分割代入で書く
props.colorと毎回書くのは少し冗長です。propsはただのオブジェクトなので、分割代入で必要なプロパティだけ取り出せます。
//List.tsx
type ListProps = {
color?: string;
}
const List = ({ color }: ListProps)=> {
return (
<ul className={`item-list ${color}`}>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
</ul>
);
}
export default List;
これはReactの機能ではなくTypeScript側の機能なので、混同しないように注意してください。
デフォルト値を設定する
分割代入では、値が渡されなかったときのデフォルト値を書けます。
//List.tsx
const List = ({ color = "green" }: ListProps)=> {
return (
<ul className={`item-list ${color}`}>
...
</ul>
);
}
//Greet.tsx
const Greet = ()=> {
return (
<div className="component">
<h3>Hello World</h3>
<List />
<List color="red" />
</div>
);
}
colorを渡さなかったほうにはundefinedが入るため、初期値のgreenが使われて緑色になります。
別の名前で受け取る
受け取る側で名前を変えたいときは、コロンで指定します。
//List.tsx
const List = ({ color: c = "green" }: ListProps)=> {
return (
<ul className={`item-list ${c}`}>
...
</ul>
);
}
ここに設定する名前は何でも構いません。この関数の中ではcという名前でcolorの値が使えます。
propsの基本ルール
基本的にコンポーネントは、propsの値によってのみ出力結果が変わるように作ります。何か表示を変えたくなったときは、props経由で値を渡すのが一般的です。
確認問題
Listコンポーネントに、リストの見出しを表示する機能を追加します。
//List.tsx
type ListProps = {
color?: string;
}
const List = ({ color = "green" }: ListProps)=> {
return (
<ul className={`item-list ${color}`}>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
</ul>
);
}
export default List;
問題
Listにtitleというpropsを追加してください。条件は以下の通りです。
-
titleは渡さなくてもよいものとする - 渡されなかった場合は
アイテム一覧と表示する -
ulタグの上にh3タグでtitleを表示する -
Greet.tsxからListを2つ読み込み、片方には買い物リストを渡し、もう片方は何も渡さない
(下に解答を記載しています)
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
解答
//List.tsx
type ListProps = {
color?: string;
title?: string;
}
const List = ({ color = "green", title = "アイテム一覧" }: ListProps)=> {
return (
<div>
<h3>{title}</h3>
<ul className={`item-list ${color}`}>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
</ul>
</div>
);
}
export default List;
//Greet.tsx
import "./Greet.css"
import List from "./List"
const Greet = ()=> {
return (
<div className="component">
<List title="買い物リスト" color="red" />
<List />
</div>
);
}
export default Greet;
ポイントは2つです。
- 渡さなくてもよいpropsなので、型に
?を付けている - デフォルト値は分割代入の中で
title = "アイテム一覧"と書いている
ulの上にh3を置くために全体をdivで囲んでいますが、ここは第六回で学んだフラグメント(<>)を使っても構いません。
チェックリスト
- propsは属性名と属性値の形で渡している
-
受け取る側で
typeを使って型を宣言している -
渡さない可能性があるpropsには型に
?を付けている -
props.xxxではなく分割代入で受け取れている - デフォルト値は分割代入の中で設定している
- 分割代入はReactではなくTypeScriptの機能だと理解している
- 別名で受け取りたいときはコロンを使うと知っている
-
propsという引数名は慣習にすぎないと分かっている - 表示を変えたいときはprops経由で渡す、という原則を意識している
第九回はここまで。
次回はpropsにいろいろな値を渡す方法について学習していきます!