エンジニア夫婦の技術日記

【React】コンポーネントってなんぞやという話


2022年8月26日
Posted by 

皆さんはReact.js、React Nativeをご存知でしょうか?

React.jsはWebアプリのUIを作成する際に使用出来るライブラリです。
JSXという、JSの中にHTMLやCSSを書くといった独自の記法が特徴です。

React NativeはクロスプラットフォームなスマホアプリをJSで開発する際に利用出来るフレームワークです。

私たち夫婦が製作中のスマホアプリはReact Nativeを利用しております。
今回はReact、React Native初学者に向けた内容になります。


Reactの基本概念

ReactもReact Nativeも共通で、基本的にコンポーネント指向という概念があります。

コンポーネント指向とはなんぞや

以下、React.js公式ページからの引用です。

コンポーネントベース

自分自身の状態を管理するカプセル化されたコンポーネントをまず作成し、これらを組み合わせることで複雑なユーザインターフェイスを構築します。

コンポーネントのロジックは、Template ではなく JavaScript そのもので書くことができるので、様々なデータをアプリケーション内で簡単に取り回すことができ、かつ DOM に状態を持たせないようにすることができます。

難しいことを言ってますね。
コンポーネントの概念を初めて知る方がこの文章を見たとき、知らないワードだらけで拒否反応を起こしてしまうのではないでしょうか?
少なくとも私はそうでした。意味が分からないワードがいくつもあると、自分が知らない言語に見えてきます。

そういった時に私が行っているのは、文章を単語に分解して読み解くという方法です。

それでは単語毎に分解して、1つ1つ見ていきましょう。

コンポーネントとは

様々なモノを作る際、流用が効くように小さい機能の単位でまとめた部品のことをコンポーネントと言います。

※案件によってコンポーネントの捉え方は変わります。
コンポーネントについてメンバー間で話がイマイチ噛み合わないと思ったときはコンポーネントの定義が違う可能性があるため、
ちゃんと認識を合わせて柔軟に考えられるようにしてください。

LEDで例えてみます。LEDは電流を与えることで光ります。

LED信号機や電光掲示板等、機械に組み込まれているLEDの「電流を与えると光る」という動作は変わりません。

このLEDのようなイメージがコンポーネントです。

コンポーネント化する利点

コンポーネント内に処理を閉じることで、スコープを狭める(影響を考える範囲を狭める)ことができます。

これは品質的な部分で役立ちます、

LEDの例で見ると信号機や電光掲示板を単体テストするとします。
その際、LEDの単体テストを実施して「電流を与えたら光る」という機能が担保出来れば、信号機や電光掲示板で同じテストをする必要が無くなる訳です。

また、アプリケーションの見た目や動きに一貫性が出てきます。

これはUX(ユーザーエクスペリエンス)の向上に役立ちます。

例えば以下2つのアプリケーションを比較した場合、直感的に使いやすいのは2のアプリだと思います。

  1. 多種多様な一貫性の無いボタンがいくつも表示されるアプリ
  2. 「登録系の処理」は青色のボタン・「削除系の処理」は赤色のボタン・ボタンの形は全て楕円で表示されるアプリ

極端な例かもしれないですが、情報時代の今日においてユーザーの目は肥えています。見た目や処理に少しでも一貫性が無いと、なんとなく違和感を覚えてしまいます。

一貫性があることは、使いやすいアプリケーションを作る上で重要な要素の1つだと思っています。

カプセル化とは

オブジェクト指向の概念です。

  • オブジェクトの状態に意図した変化を起こせる
  • 意図しない変化は起こさせない

というオブジェクトの作りです。

例えでよく出てくるのはカプセルの薬とかだと思いますが、正直私はこの例えでは理解しづらかったので自分なりのたとえを考えました。

湯煎するタイプのレトルトカレーで考えてみます。
これから話す内容について、レトルトカレーがカプセル化されているモノと捉えてください。

レトルトカレーを湯煎する際にレトルトパックごとお湯に入れます。

レトルトパックごと入れることで、中のカレールーの温度は上がります。
ですがカレールーとお湯の間にはレトルトパックの壁があるので混ざりません。

  • 意図した変化を起こせる:カレールーの温度を上げる
  • 意図しない変化は起こさせない:カレールーとお湯が混ざらない

これがカプセル化です。

自分自身の状態を管理するカプセル化されたコンポーネント

更にイメージを鮮明にするために、コンポーネントやカプセル化を「人」で置き換えてみます。

人は「歩く」「食べる」「寝る」等様々な機能があります。細かい動作は違いますが、大きな動作は変わりません。

これをコンポーネントと捉えることが出来ます。

また、人は日々「記憶」を蓄積していきますが同じ「記憶」を共有している人は居ません。
各々が違う記憶を持っていることはカプセル化されていると言えるのではないでしょうか?

つまりコンポーネントベースとは、「人」のような部品をいくつも作って、組み合わせて、画面を作りあげていくという考え方になります。


jsx

先述した通りReactはjsxファイルにjs、html、cssをまとめて書きます。

コンポーネントに必要な内容を単一ファイルにまとめて書くことで、コンポーネントベースの考え方を実現しているという訳ですね。


props

React、React Nativeどちらも、コンポーネントにはpropsと言って、任意の入力値を渡すことが出来る機能があります。
これにより、基本的なコンポーネントの動きを踏襲しつつ違った結果を得られるようにすることができます。

このpropsの仕組みについて、「何を出来るのかは分かるけど言葉のみを理解している気がする。解説が欲しい。」と、以前妻に解説を求められたことがあったのでその内容をご紹介します。

「人」をコンポーネント、「村」を画面として例えてみます。

やりたいこと、コンポーネントの前提を以下とします。

  • やりたいこと
    • 村にAさん、Bさんを配置したい。Aさんを剣士、Bさんを魔法使いにしたい。
  • 前提
    1. 人コンポーネントのpropsには「名前」「持ち物」の2つがある
    2. 人コンポーネントは、propsの「持ち物」がなんであろうと「振る」という動作を実行する
interface I人 {
    名前: string;
    持ち物: I持ち物;
}

interface I持ち物 {
    振る: Function;
}

const 人 = (props:I人) => {
    const { 名前, 持ち物 } = props;
    持ち物.振る();
}

export default 人;

では村にAさんを配置してみましょう。

import 人 from "etc...";

const 村 = () => {
    const 剣 = () => {
        const 振る = () => {
            対象物を切る();
        }
    }

    const 対象物を切る = () => {
        etc...
    }

    return (
        <div>
            <人 名前=゙Aさん゙
                持ち物={剣} />
        </div>
    );
}

これでAさんは剣を振り、対象物を切る剣士になれました。

次にBさんです。

import 人 from "etc...";

const 村 = () => {
    const 剣 = () => {
        const 振る = () => {
            対象物を切る();
        }
    }

    const 対象物を切る = () => {
        etc...
    }

    const 杖 = () => {
        const 振る = () => {
            魔法を出す();
        }
    }

    const 魔法を出す = () => {
        etc...
    }

    return (
        <div>
            <人 名前=゙Aさん゙
                持ち物={剣} />
            <人 名前=゙Bさん゙
                持ち物={杖}/>
        </div>
    );
}

これでBさんは杖を振って魔法を出す、魔法使いになれました。

このように、持ち物を振るという動きは踏襲していますが、Aさんは対象物を切る、Bさんは魔法を出すといった違う結果を得ることが出来ました。

これがコンポーネントのpropsの利点です。

個人的にはオブジェクト指向のクラスの考え方に似ていると思っています。


state

Reactはstateという機能で、コンポーネントの中に情報を保持しておくことが出来ます。

stateの情報がリセットされるのは画面を再表示した時等です。

コンポーネントのstateはカプセル化されています。
そのため他のコンポーネントのstateに影響されません。

propsで挙げた例ですと、AさんとBさんは同じ人コンポーネントを使っています。

Aさんの状態が毒になったとします。
その状態は飽くまでAさんのみに影響があるもので、Bさんには影響がありません。

という感じです。

Reactはstateに変化があった時、stateが影響するコンポーネントだけを再レンダリング(再表示)するという仕組みがあります。

こうすることで、表示する処理を高速化しています。

文書を書く時に「文書全体を書き直す」のと「必要な箇所だけ書き直す」では後者の方が早いですよね。それと似たようなニュアンスです。


まとめ

  • Reactはコンポーネントベース
  • コンポーネントとは、流用が効くように小さい機能の単位でまとめた部品
  • コンポーネントはpropsを利用してカスタマイズ出来るようにすることが出来る
  • コンポーネントはstateに情報を保持しておくことが出来る
  • stateは他コンポーネントの影響を受けない

コメントを書く