【入門編】 styleとclassNameのProps設計 – React実践ガイド

こんにちは!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: 標準の青いボタンのまま使う /}
alert(‘購入します!’)}>
通常購入する

{/ パターンB: classNameを追加して、色を目立つ赤色に変えてみる /}
alert(‘急いで購入します!’)}
>
今すぐ急いで購入!

{/ パターンC: styleを使って、その場で文字サイズを直指定してみる /}

特大サイズで買う

);
};

見事に、親である`CheckoutPage`から自由自在に見た目がカスタマイズできるようになりましたね!これが、再利用性の高いコンポーネント設計の第一歩です。

—

最後に:完璧を目指さなくて大丈夫

初めて`className`や`style`の型付けを見たときは、「なんだかお作法が多くて難しそう…」と感じたかもしれません。でも大丈夫。一歩ずつ、今日覚えたコードを自分のエディタにコピペして、動かして、わざとエラーを出してみたりしながら体で覚えていけばいいんです。

現場のシニアエンジニアたちも、最初はみんな同じところでつまずいてきました。
あなたの書くコードが、誰かの使いやすい「最高のレゴブロック」になる日を、私は心から応援しています!

コメント

タイトルとURLをコピーしました