こんにちは!Reactの学習、楽しく進められていますか?
「组件(コンポーネント)をたくさん作れるようになってきたぞ!」というワクワクする反面、こんな悩みに出会ったことはありませんか?
「親から受け取ったたくさんのProps(プロパティ)を、そのまま下の子コンポーネントにパスしたいだけなのに、わざわざ一つずつ名前を指定して渡すのって、なんだかすごく面倒くさい……」
そう、何個もあるPropsを一個ずつ `title={title}` `disabled={disabled}` `onClick={onClick}` ……なんて書いていたら、コードは長くなるし、後から親の仕様が変わったときに修正地獄になってしまいますよね。
大丈夫です、安心してください!
今回は、そんな面倒くささを一気に解決してくれる、React開発の現場でもめちゃくちゃお世話になる「Propsのレスト・スプレッド構文(`{…props}`)」について、優しく紐解いていきましょう。
—
宅配便の「中身を開けずにそのままお引越し」でイメージしよう
この `…props` という書き方、なんだか見慣れない三点リーダー(`…`)があって難しそうに見えますよね。でも、身近な例えで考えてみると、拍子抜けするくらいシンプルです。
例えば、あなたが引越しをするとします。
ダンボールの中に、お皿や本、服がぎっしり詰まっています。このダンボールを新しいお部屋に運ぶとき、わざわざ中身を全部一度出して、一枚ずつ一枚ずつ手で持って新しい部屋に運びますか?
……そんなことしたら、気が遠くなりますよね!
普通は、「ダンボールのフタを閉じたまま、中身はそのままで、ドサッと次の部屋に運び込む」はずです。
Reactの `…props` は、まさにこの「ダンボールごと次のコンポーネントへパスする技」なんです。
—
具体的にどんな時に使うの?(ラッパーコンポーネントの悲劇を防ぐ)
Web制作やアプリ開発をしていると、「既存のHTMLタグや別コンポーネントを、少しだけ自分好みにカスタマイズして使い回したい」という場面に本当によく出会います。
例えば、アプリ全体で統一感を持たせるために、独自の「カッコいいボタンプリセット」を作りたいとします。
従来の「力技」な書き方(ちょっと大変な例)
もし、レスト・スプレッド構文を知らなかったら、私たちはこう書くかもしれません。
// 親から受け取った全てのPropsを手動で仕分けて渡す、ちょっと大変なコンポーネント
function MyButton({ text, color, onClick, disabled, type, className }) {
return (
);
}
「うわっ、大変そう…」と思いましたよね?その直感は大正解です。
もし後になって「あ、やっぱり `aria-label` も渡せるようにしなきゃ」「`onMouseEnter` も必要だ!」となったら、このコードの引数も `return` の中身も、何箇所も書き直す必要があります。これではコードを書くのが嫌になってしまいますよね。
—
レスト・スプレッド構文で、コードをスマートにしよう!
ここで登場するのが、今回の主役であるスプレッド構文(`…props`)です。
まずは、実際のコードを見てみてください。驚くほどスッキリしますよ。
import React from ‘react’;
// ① MyButtonに入ってきたPropsを、残らず「props」というカバンにひとまとめにします
function MyButton({ children, …props }) {
return (
);
}
// 使い方
export default function App() {
return (
disabled={false}
aria-label=”送信ボタン”
>
ポチッと押してね
);
}
どうですか?さっきのコードと比べて、圧倒的にスッキリしましたよね!
ここで何が起きているのか、魔法のタネをバラすように優しく解説します。
1. `{ children, …props }` (レスト構文)
最初に受け取ったPropsの中から、`children`(子要素)だけを特別に取り出し、「それ以外の残りのPropsは、全部まとめて `props` という名前のバッグに詰め込んじゃおう!」とやっています。この「残りをまとめる `…`」をレスト(Rest=残り)構文と呼びます。
2. `{…props}` (スプレッド構文)
そして、HTMLの `
これなら、親からどんなProps(`onClick` や `id` や `data-` 属性など)が追加で送られてきても、コンポーネント側を一切書き直すことなく、そのまま綺麗に奥へパスしてあげることができます。拡張性が高くて、本当に気持ちがいい書き方なんです!
—
初学者がつまずきやすい!知っておくべき2つのポイント
この `…props` はすごく便利な反面、現場でよくある「うっかりミス」がいくつかあります。ここを押さえておけば、もう怖くありません!
1. 順番(上書きのルール)に気をつけよう
JavaScriptのスプレッド構文は、「後に書いたものが、前に書いたものを上書きする」というルールがあります。
例えば、次のようなコードを書いたとします。
function DangerButton(props) {
return (
);
}
// 親側でこう使われた場合:
//
この場合、親が「青にして!」と言っていても、コンポーネント側で `style={{ backgroundColor: ‘red’ }}` を書いた後に `{…props}` で上書きしようとすると、親の指定した「青」が勝ちます。
逆に、コンポーネント側で強制的にスタイルを固定したい場合は、`{…props}` を書いた「後」に独自のプロパティを書くようにしましょう。
function FixedButton(props) {
return (
);
}
この「前後に置く位置による上書きの魔力」、最初は混乱しやすいですが、レイアウトや制御を強制したいときの大切なテクニックです。
2. TypeScriptを使うときの型付けはどうするの?
「よし、TypeScriptで書こう!」と思ったとき、この `…props` にどう型を付けたらいいか迷いがちです。でも、これも基本の型を継承してあげれば怖くありません。
import React, { ComponentPropsWithoutRef } from ‘react’;
// 「普通のbuttonタグが持っているProps」を丸ごと型として拝借しちゃいます
type MyButtonProps = ComponentPropsWithoutRef<'button'> & {
// もし独自のオリジナルPropsを追加したい場合はここに書く
customColor?: string;
};
export function TypedButton({ children, customColor, …props }: MyButtonProps) {
return (
);
}
`ComponentPropsWithoutRef<'button'>`(または `React.ComponentProps<'button'>`)を使うことで、「HTMLのボタン要素が本来持っているすべての型(`onClick`, `disabled`, `aria-` など)」を自動で引き継ぐことができます。これで型安全なコードの出来上がりです!
—
まとめ
今回は、Reactのコンポーネント合成を何倍もエレガントにしてくれるPropsのレスト・スプレッド構文(`{…props}`)についてお話ししました。
- レスト構文 (`{ children, …props }`) で、不要なものを省いて残りのPropsをひとまとめにする。
- スプレッド構文 (`{…props}`) で、まとめたPropsを次の要素へ一気に受け渡す。
- 引越しのダンボールをイメージすれば、動きがスッキリ理解できる!
最初は少し魔法のように感じるかもしれませんが、一度この書き方に慣れると、コードの量も減るしメンテナンスもしやすくなって、もう元の書き方には戻れなくなっちゃいます(笑)。
一歩一歩、確実にReactの引き出しを増やしていきましょう。
あなたの前端(フロントエンド)開発の旅を、心から応援しています!また次回の記事でお会いしましょう!

コメント