こんにちは!Reactの世界へようこそ。チーフアーキテクトの私です。
Reactを学び始めると、必ずと言っていいほど直面する壁があります。それが「作ったコンポーネントの見た目を、後からいじりたい時にどうすればいいのか?」という問題です。
例えば、「ボタン」というコンポーネントを作ったとします。普段は青色なんだけど、ある場所では赤色にしたい、あるいは少しだけ右に寄せたい……そんな時、あなたならどうしますか?
今回は、現場のプロも毎日使っている`className`と`style`を使ったスマートなスタイルの受け渡し術について、身近な例え話を交えながら、優しく、そして徹底的に解説していきますね。
大丈夫、最初は誰でも「あれっ、どう型を付ければいいんだっけ?」と手が止まるものですよ。一緒に一つずつ紐解いていきましょう!
—
1. コンポーネントは「オーダーメイドのレゴブロック」
まず、Reactのコンポーネントを想像してみてください。イメージとしては「組み立て式の便利な家具」や「オーダーメイドのレゴブロック」です。
あなたが「使いやすいボタン入れ物」というパーツを作ったとします。基本の設計図は決まっていますが、使う人(親コンポーネント)によっては、「今回はリビングに置くから茶色にしたい」「今回は子供部屋だから黄色にしたい」という要望が出てきますよね。
Reactの世界では、この「外側からのカスタマイズ要望」を受け取るための窓口が、`className`であり、`style`なんです。
ざっくりイメージしてみよう
- `className` = 「あらかじめ用意されたおめかし用の服(CSSクラス名)をそのまま着せる」
- `style` = 「その場で直接、寸法や色を細かく指定してマジックで書き込む(インラインスタイル)」
実務では、基本的にはCSSクラス(Tailwind CSSやCSS Modulesなど)で管理することが多いので`className`が主役になりますが、動的に変わる値を渡すために`style`も知っておく必要があります。
—
2. 初学者がつまずきやすい「型の迷子」
TypeScriptを使っていると、ここで最初の関門がやってきます。
「あれ、外部から`className`を受け取るってことは、TypeScriptにどう教えればいいんだ?」と。
安心してください。Reactには、こうしたHTMLの標準属性をまとめて引き受けてくれる、とっても便利な「型のお助けマン」がちゃんと用意されています。
百聞は一見に如かず、まずは実際に動くコードを見てみましょう。
優しいボタンコンポーネントの実装例
以下のコードは、親から渡された`className`と`style`を、綺麗に受け取って自分のHTML要素に反映させる「お利口なボタン」の例です。
import React from ‘react’;
// 1. プロパティ(Props)の型を定義します
// React.ComponentPropsWithoutRef<'button'> を使うと、
// 「普通のHTMLのボタンが持っている属性(onClickやdisabledなど)」を丸ごと引き継げます!
export interface MyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
// ボタンの中に表示するテキストや要素
children: React.ReactNode;
// classNameとstyleは、HTMLの仕様上、実は「あってもなくてもいい(オプショナル)」ものなので
// 「?」をつけておくのが優しさのコツです。
className?: string;
style?: React.CSSProperties; // React専用のスタイルの型
}
export const MyButton: React.FC
children,
className = ”, // 万が一渡されなかった時のためのデフォルト値(空っぽ)
style,
…restProps // 他のonClickなどのイベントもまとめて受け取る器
}) => {
return (
// 受け取った className や style を、そのまま実際の
ここがポイント!
- `React.CSSProperties`: `style`プロパティに型をつけるときは、この専用の型を指定します。これのおかげで、エディタが `backgroundColor` や `fontSize` などの候補を賢くサジェストしてくれるようになります。
- テンプレートリテラル(“ `… ${className}` “): コンポーネントが最初から持っているデフォルトのスタイルと、外から親が追加してきた`className`を、仲良く合体させています。
—
3. 現場で使える「スタイルマージ(結合)」の知恵
さて、ここで少しだけ実務的なテクニックをご紹介します。
もし、親コンポーネントから渡された`style`と、子コンポーネント(今のボタン)自身が持っているデフォルトの`style`がぶつかったらどうなるでしょうか?
お察しの通り、「後から渡されたもの(親の意図)」が勝つ(上書きする)のが自然な挙動ですよね。
JavaScriptのオブジェクトのスプレッド構文(`…`)を使うと、この上書きがとてもスマートに実現できます。
// 子コンポーネントの中でのスタイルのマージ例
const defaultStyle: React.CSSProperties = {
cursor: ‘pointer’,
boxShadow: ‘0 2px 4px rgba(0,0,0,0.1)’,
};
// 親から渡された style があれば、defaultStyle の後ろに重ねて上書きする!
const mergedStyles: React.CSSProperties = {
…defaultStyle,
…style, // 親からのスタイルが後から適用されるので、上書きされる
};
これを知っているだけでもう、「あ、スタイルがうまく反映されない!」というパニックから解放されますよ。
—
4. 実際に使ってみよう(お買い物の流れ)
定義したコンポーネントを、親であるページ側から使ってみましょう。ここでは、お買い物の注文確定ボタンをイメージしてみてください。
import React from ‘react’;
import { MyButton } from ‘./MyButton’;
export const CheckoutPage: React.FC = () => {
return (
お支払い画面
{/ パターンA: 標準の青いボタンのまま使う /}
通常購入する
{/ パターンB: classNameを追加して、色を目立つ赤色に変えてみる /}
>
今すぐ急いで購入!
{/ パターンC: styleを使って、その場で文字サイズを直指定してみる /}
特大サイズで買う
);
};
見事に、親である`CheckoutPage`から自由自在に見た目がカスタマイズできるようになりましたね!これが、再利用性の高いコンポーネント設計の第一歩です。
—
最後に:完璧を目指さなくて大丈夫
初めて`className`や`style`の型付けを見たときは、「なんだかお作法が多くて難しそう…」と感じたかもしれません。でも大丈夫。一歩ずつ、今日覚えたコードを自分のエディタにコピペして、動かして、わざとエラーを出してみたりしながら体で覚えていけばいいんです。
現場のシニアエンジニアたちも、最初はみんな同じところでつまずいてきました。
あなたの書くコードが、誰かの使いやすい「最高のレゴブロック」になる日を、私は心から応援しています!

コメント