ReactのPropsとは?渡し方・受け取り方をTypeScript例で解説

当サイトでは一部リンクに広告が含まれています
Reactアイコン
目次

ReactのPropsとは?

React(リアクト)とは、Facebookが開発したJavaScriptのライブラリの一つで、ユーザーインターフェースの作成に特化しています。
Reactの強力な機能の一つは、コンポーネントという概念です。
コンポーネントとは、再利用可能な独立した部品のことで、UIを構成する基本的な単位と言えます。

しかし、コンポーネントが有用であるためには、それが再利用可能であることが重要です。
同じコンポーネントを異なるデータで何度も使い回すことができると、コードの繰り返しを減らすことができ、保守も容易になります。

ここでProps(プロップス)の出番です。
Propsとは、親コンポーネントから子コンポーネントへデータを渡すための仕組みです。
親コンポーネントから渡されたデータ(Props)によって、子コンポーネントの表示内容や振る舞いをカスタマイズすることができます。

つまり、Propsはコンポーネントが異なるデータを受け取り、そのデータに基づいて異なる振る舞いをするための“橋渡し役”とも言えます。

なぜPropsが必要なのか?

Propsの一番の魅力は、同じコンポーネントを再利用して、異なる結果を得られることです。

例えば、あるWebサイトにログインしているユーザーの情報を表示するためのコンポーネントを考えてみましょう。
このコンポーネントは、ユーザーの名前とログイン状況(ログインしているかどうか)を表示します。

// ユーザーの名前とログイン状況を表示するコンポーネント
const User: React.FC = () => {
  return (
    <div>
      田中さん、こんにちは!
      <br />
      ログイン中です。
    </div>
  );
};

しかし、ユーザーの名前やログイン状況はユーザーごとに異なります。
そのため、本来は、ユーザーごとに異なる情報を表示するコンポーネントを作成する必要が出てきてしまいます。。。

// ユーザーの名前とログイン状況を表示するコンポーネント
const UserTanaka: React.FC = () => {
  return (
    <div>
      田中さん、こんにちは!
      <br />
      ログイン中です。
    </div>
  );
};

// ユーザーの名前とログイン状況を表示するコンポーネント
const UserSato: React.FC = () => {
  return (
    <div>
      佐藤さん、こんにちは!
      <br />
      ログイン中です。
    </div>
  );
};

そこで、これらの情報をPropsとしてコンポーネントに渡すことで、同じコンポーネントを使って、異なるユーザー情報を表示することが可能になります。

// ユーザーの名前とログイン状況を表示するコンポーネント
type UserProps = {
  name: string;  // ユーザーの名前
  isLoggedIn: boolean;  // ログイン状況
};

const User: React.FC<UserProps> = (props) => {
  return (
    <div>
      {props.name}さん、こんにちは!
      <br />
      {props.isLoggedIn ? "ログイン中です。" : "ログインしていません。"}
    </div>
  );
};

// Userコンポーネントを利用する例
const App: React.FC = () => {
  return (
    <>
      <User name="田中" isLoggedIn={true} />
      <User name="佐藤" isLoggedIn={false} />
    </>
  )
};

このように、Propsを使うことで、同じコンポーネントを様々なデータで使い回すことができ、コードの量を減らし、保守性を向上させることができます。

コンポーネント指向のフレームワークでは、Propsのような機能が必須となっています。

Propsの使い方

では、Props の使い方を学びましょう。

Propsの基本的な渡し方

Propsを渡すには、まずコンポーネントを作ります。
その後、そのコンポーネントに情報を渡すときにPropsを使います。

以下に、Propsを使ったソースコードの例を示します。

// ユーザーの名前を表示するコンポーネント
type UserProps = {
  name: string;  // ユーザーの名前
};

const User: React.FC<UserProps> = (props) => {
  return <div>{props.name}さん、こんにちは!</div>;
};

// Userコンポーネントを利用する例
const App: React.FC = () => {
  return <User name="田中" />;
};

この例では、まずUserPropsという型を作ります。
この型はユーザーの名前(name)だけを持つオブジェクトの型を表しています。

次に、その型のPropsを受け取るUserというコンポーネントを作ります

このコンポーネントは、Propsで受け取った名前(name)を使って、「田中さん、こんにちは!」というメッセージを表示します。

最後に、AppというコンポーネントでUserコンポーネントを使います。
この時、Userコンポーネントに「田中」という名前をPropsとして渡します。

このように、Propsを使うと、あるコンポーネントから別のコンポーネントにデータを渡すことができます。

Propsの受け取り方

Propsを受け取るには、コンポーネントの引数(props)を使います。

type UserProps = {
  name: string;  // ユーザーの名前
};

const User: React.FC<UserProps> = (props) => {
  return <div>{props.name}さん、こんにちは!</div>;
};

export default User;

上記の例では、Userコンポーネントがpropsという引数でPropsを受け取り、その中のnameを表示しています。

別の書き方も見てみましょう。

type UserProps = {
  name: string;  // ユーザーの名前
};

export default function User(props: UserProps) {
  return <div>{props.name}さん、こんにちは!</div>;
}

どちらも同じようにPropsを受け取ることができます。

Propsの型

Propsの型は、React.FCのジェネリクスで指定します。

type UserProps = {
  name: string;      // ユーザーの名前
  isLoggedIn: boolean; // ログインしているかどうか
};

上記の例では、UserPropsという型を作り、その中にnameisLoggedInという2つのプロパティを持つオブジェクトの型を指定しています。

const User: React.FC<UserProps> = (props) => {
  return (
    <div>
      {props.isLoggedIn
        ? <p>{props.name}さん、こんにちは!ログインしています。</p>
        : <p>ゲストさん、こんにちは!ログインしてください。</p>
      }
    </div>
  );
};

次に、Userコンポーネントの引数にUserPropsという型を指定しています。
これにより、UserコンポーネントはnameisLoggedInという2つのプロパティを持つオブジェクトを受け取ることができるようになります。

const App: React.FC = () => {
  return (
    <div>
      <User name="田中" isLoggedIn={true} />
      <User name="ゲスト" isLoggedIn={false} />
    </div>
  );
};

Propsの省略記法

Propsの型を指定するとき、React.FCのジェネリクスを使わずに、React.FCの引数に直接型を指定することもできます。

const User: React.FC<{ name: string; isLoggedIn: boolean; }> = (props) => {
  return (
    <div>
      {props.isLoggedIn
        ? <p>{props.name}さん、こんにちは!ログインしています。</p>
        : <p>ゲストさん、こんにちは!ログインしてください。</p>
      }
    </div>
  );
};

このように、React.FCの引数に直接型を指定する場合、React.FCの後に<>を使って型を指定します。

【具体例】Propsを使ったログイン状況の表示

この例では、ユーザーがログインしているかどうかによって表示を変えるコンポーネントを作ります。

type UserProps = {
  name: string;      // ユーザーの名前
  isLoggedIn: boolean; // ログインしているかどうか
};

const User: React.FC<UserProps> = (props) => {
  return (
    <div>
      {props.isLoggedIn
        ? <p>{props.name}さん、こんにちは!ログインしています。</p>
        : <p>ゲストさん、こんにちは!ログインしてください。</p>
      }
    </div>
  );
};

const App: React.FC = () => {
  return (
    <div>
      <User name="田中" isLoggedIn={true} />
      <User name="ゲスト" isLoggedIn={false} />
    </div>
  );
};

この例では、まずUserPropsという型を作ります。
この型は、ユーザーの名前(name)とログイン状況(isLoggedIn)を持つオブジェクトの型を表しています。

次に、その型のPropsを受け取るUserというコンポーネントを作ります。
このコンポーネントは、Propsで受け取った名前(name)とログイン状況(isLoggedIn)によって、表示するメッセージを変えます。

最後に、AppというコンポーネントでUserコンポーネントを使います。
この時、Userコンポーネントに「田中」という名前とログイン状況(true)をPropsとして渡し、別のUserコンポーネントに「ゲスト」という名前とログイン状況(false)をPropsとして渡します。

これにより、「田中さん、こんにちは!ログインしています。」と「ゲストさん、こんにちは!ログインしてください。」という2つの異なるメッセージが表示されます。

このように、Propsを使うことで、同じコンポーネントでも渡すデータによって表示を変えることが可能になります。これが、Propsの一つの大きなメリットです。

注意点1: Propsは読み取り専用

注意点としては、Propsは読み取り専用です。
つまり、コンポーネントの中でPropsを変更することはできません。
Propsを変更したい場合は、ReactのState(状態)を使う必要があります。

NG例:

type UserProps = {
  name: string;  // ユーザーの名前
};

const User: React.FC<UserProps> = (props) => {
  props.name = "鈴木";  // NG!Propsは読み取り専用
  return <div>{props.name}さん、こんにちは!</div>;
};

OK例:

type UserProps = {
  name: string;  // ユーザーの名前
};

const User: React.FC<UserProps> = (props) => {
  const [name, setName] = useState(props.name);  // Stateを使ってPropsを変更
  return <div>{name}さん、こんにちは!</div>;
};

了解しました。では、次にPropsの使い方における注意点として、「多階層でのPropsの受け渡し」について説明します。

注意点2: ネスト(入れ子)構造におけるPropsの受け渡し

Reactのコンポーネントがネスト(入れ子)になった場合、つまり、親コンポーネントから子コンポーネント、さらにその子コンポーネントへとPropsを渡すような場合について注意が必要です。これを「Propsのドリルダウン」とも呼びます。

例えば以下のようなコードがあったとしましょう。

type GrandChildProps = {
  message: string;
};

const GrandChild: React.FC<GrandChildProps> = (props) => {
  return <p>{props.message}</p>;
};

type ChildProps = {
  message: string;
};

const Child: React.FC<ChildProps> = (props) => {
  return <GrandChild message={props.message} />;
};

type ParentProps = {
  message: string;
};

const Parent: React.FC<ParentProps> = (props) => {
  return <Child message={props.message} />;
};

const App: React.FC = () => {
  return <Parent message="こんにちは、世界!" />;
};

このコードでは、AppコンポーネントからParentコンポーネント、Childコンポーネントを経てGrandChildコンポーネントへとPropsが渡されています。
しかし、このように多階層に渡るPropsの受け渡しは、コードの可読性を下げ、デバッグを難しくする可能性があります。

具体的には、「どのコンポーネントがどのPropsをどこで使っているのか」を把握するのが難しくなります。
また、Propsの名前や型が途中で変更されると、それが影響する全てのコンポーネントを修正する必要が出てきます。

そこで、このような問題を解決するためには、以下のような対策が考えられます。

  1. コンテクスト(Context)を使う: Reactには、コンテクストという機能があります。これを使うと、多階層に渡るPropsの受け渡しを避け、コンポーネント間でのデータの共有を容易にすることができます。
  2. 状態管理ライブラリを使う: ReduxやMobXなどの状態管理ライブラリを使うと、アプリケーションの状態を一元管理することができ、Propsのドリルダウンを避けることができます。

このような手法を使うことで、Propsの使い方によるコードの複雑さを減らし、より良いコードを書くことができます。

React を効率的に身につける勉強法は?

React には興味があっても、プログラミング学習をはじめたばかりであれば、以下のような疑問を持つかもしれません。

  • Reactエンジニアとして活躍するために何をすればいい?
  • 何から勉強すればいいんだろう?
  • 絶対に転職を成功させるには?

React は習得が比較的難しいため、勉強法の選び方を間違うと時間・労力・お金が無駄になってしまいます…。

そのため、こちらの記事を参考に、ご自身に最適な学習方法を選んでみませんか?

目次