NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

初学者必見!!! Reactってどんなもの?~Reactのメリットについて知ろう~



はじめに

はじめまして、こんにちは。新入社員の嘉地です。
大学生になってすぐの頃、キーボードをL打ちしていたほど機械に弱かった私が、ITの道に進み、早いものでもう1年が経とうとしています。
年々、1年の経過スピードが早くなっていることに、かなりの老いと恐怖を感じております。

そんな私は現在、Reactというものを使って開発を進めています。
私自身、Reactも、ましてやJavaScriptも「初めまして」でした。
そのため今回は、Reactについて右も左もわからないという人に向けて、
Reactの基本中の基本の動きについて、具体的に分かりやすく解説していきたいと思います。


そもそもReactって何者??

めちゃくちゃ簡単に言うと、マークアップを各機能ごとに切り出して、HTMLを動的に書けるものです。 というのも、Reactはマークアップを返すことができるからです。

そのため、HTMLをずらーっと1つのファイルに書くのではなく、
マークアップの一部を切り出して、機能ごとにグループ化したり、マークアップの中で繰り返し使いたいもの(ボタンやテキストフォーム等)を共通コンポーネントとして切り出すことができます。こうすることで動的なHTMLを書くことが可能になります。
あとは、それを使いたい箇所で呼び出すことで、マークアップの中で使用することができるものです。

では次に、下記の3つについて、簡単にコードと動きを解説していきたいと思います。
1.マークアップの中の一部を切り出して、機能ごとにグループ化してみる
2.繰り返し使いたいもの(ボタンやテキストフォーム等)を共通コンポーネントとして切り出す
3.動的HTMLの作成

その他、Reactについては公式ドキュメントをご参照ください。 react.dev


Reactのメリットをさくっと体感してみる

マークアップの中の一部を切り出して、機能ごとにグループ化してみる

まず、Reactを使用する上で、使用する側(親コンポーネント)と、使用される側(子コンポーネント)の考え方が重要になってきます。
各コンポーネントがネスト状になってHTMLを形成するのが特徴的です(参照:図1Reactで書いたHTML)。
それを踏まえてここでは、HTMLを項目ごとにコンポーネントに切り出してみましょう。


【ここで実施すること】

・ 下記の自己紹介のマークアップを項目ごと(名前、好きなもの、苦手なもの)に分ける
・ 項目ごとに分かれたマークアップを親クラス(Parents.tsx)で呼び出して縦に並べる(参照:図1 Reactで書いたHTML)

【自己紹介のマークアップ】

<h1>自己紹介</h1>
<h3>名前</h3>
<p>嘉地 華香(かじ はるか)</p> 
//ここまでで名前という項目
<h3>好きなもの</h3>
<ul>
    <li>ジョジョの奇妙な冒険(特に2部が好き)</li>
    <li>ディズニー</li>
    <li>数の子</li>
</ul>
//ここまでで好きなものという項目
<h3>苦手なもの</h3>
<ul>
    <li>しいたけ</li>
    <li>着ぐるみ</li>
    <li>大きい建物や木</li>
</ul>
//ここまでで苦手なものという項目



【フォルダ構成について】

src/
 ├ Parents.tsx // 3つのコンポーネントをまとめて表示
 ├ child1/
  └ Name.tsx //名前を表示するコンポーネント
 ├ child2/
  └ Like.tsx //好きなものを表示するコンポーネント
 ├ child3/
  └ Dislike.tsx //苦手なものを表示するコンポーネント

図1 Reactで書いたHTML

src/child1/Name.tsx
まずは、名前を返すコンポーネント(Name.tsx)を作成します。

export const Name  = () => {
   return (
       <h3>名前</h3>
       <p>嘉地 華香(かじ はるか)</p> 
   );
};

コンポーネントを返したいときは、上記のように、コンポーネントを定義し、このコンポーネントを呼び出したときに返すマークアップをreturnで返します。

src/child2/Like.tsx
好きなものを返すコンポーネント(Like.tsx)を作成します。

export const Like  = () => {
   return (
       <h3>好きなもの</h3>
       <ul>
           <li>ジョジョの奇妙な冒険(特に2部が好き)</li>
           <li>ディズニー</li>
           <li>数の子</li>
       </ul>
   );
};


src/child3/Dislike.tsx
苦手なものを返すコンポーネント(Dislike.tsx)を作成します。

export const Dislike  = () => {
   return (
        <h3>苦手なもの</h3>
       <ul>
           <li>しいたけ</li>
           <li>着ぐるみ</li>
           <li>大きい建物や木</li>
       </ul>
   );
};


src/Parents.tsx

import { Name } from './child1/Name.tsx';
import { Like } from './child2/Like.tsx';
import { Dislike } from './child3/Dislike.tsx';

export const Parents = () => {
   return (
        <h1>自己紹介</h1>
        <Name />  //Nameコンポーネントを呼ぶ
        <Like />  //Likeコンポーネントを呼ぶ
        <Dislike /> //Dislikeコンポーネントを呼ぶ
   );
};

これら3つの子コンポーネントをParents.tsx(親コンポーネント)から呼び出すことで、自己紹介をそれぞれの項目ごとにコンポーネントに切り出し、 そのコンポーネントを自己紹介というコンポーネントで括ることができました。これで、図1のReactで書いたHTMLが完成しました。

繰り返し使いたいもの(ボタンやテキストフォーム等)を共通コンポーネントとして切り出す

共通コンポーネントは、いわゆる “ひな型” です。
そのためには、親コンポーネントから子コンポーネント(共通コンポーネント)に値を渡し、子コンポーネントでその値を受け取りHTMLに埋め込むという機能を実装することになります。
この機能を実装するには、Propsというものを使います。Propsとは、いわゆる引数です。
引数といえど、親から子へという一方向にしか渡すことはできません。では、実例を交えて解説していきます。

先ほど使用した自己紹介のHTMLを再利用していきます。Like.tsxとDislike.tsxの内容ですが、どちらも箇条書きのマークアップになっています。
では、こちらの箇条書きのマークアップを共通コンポーネントととして切り出してみましょう。

【ここで実施すること】

・ 箇条書きのひな形を作成する(新しくcomponentフォルダを作成し、その直下にbulletPoints.tsxを作成する)
・ その箇条書きのひな形を使って、先ほどと同様のHTMLを作成する

【フォルダ構成について】

src/
 ├ Parents.tsx
 ├ child1/
  └ Name.tsx
 ├ child2/
  └ Like.tsx //修正を加える(BulletPoint.tsxを使って箇条書きを実装する)
 ├ child3/
  └ Dislike.tsx //修正を加える(BulletPoint.tsxを使って箇条書きを実装する)
 ├ component/
  └ BulletPoints.tsx //新たに作成(箇条書きのひな形)



src/component/BulletPoint.tsx

//受け取るPropsの型を定義
type Props = {
     title: string;
     item1: string;
     item2: string;
     item3: string;
};

export const BulletPoint = ( { title, item1, item2, item3 } : Props ) => {
//受け取るPropsを括弧の中に記載
  return (
         <h3>{ title }</h3>
       <ul>
           <li>{ item1 }</li>
           <li>{ item2 }</li>
           <li>{ item3 }</li>
       </ul>
  );
};

上記のように、共通コンポーネントが呼び出された際に、受け取る変数を括弧の中に定義します。
受け取ったPropsをマークアップの中で使用するときは、中括弧を用います。Like.tsx、Dislike.tsxで、この共通コンポーネントを使って箇条書きのマークアップを作成します。

src/child2/Like.tsx

import { BulletPoint } from '../component/BulletPoint.tsx';

export const Like  = () => {
   return (
       <BulletPoint
//BulletPointに渡したい値をProps名=で書いていく
          title="好きなもの" 
          item1="ジョジョの奇妙な冒険(特に2部が好き)"
          item2="ディズニー"
          item3="数の子"
         />
   );
};



src/child3/Dislike.tsx

import { BulletPoint } from '../component/BulletPoint.tsx';

export const Name  = () => {
   return (
       <BulletPoint
          title="苦手なもの" 
          item1="しいたけ"
          item2="着ぐるみ"
          item3="大きい建物や木"
         />
   );
};

上記のように共通コンポーネントを使用する側では、共通コンポーネントで定義したProps名と対応させて、具体的に入れたい値を渡します。こうすることにより、箇条書きのマークアップに変更を加えたいとき等、共通コンポーネントを変更するのみで対応が可能になります。
上記では、Propsに値をひとつひとつ渡していますが、箇条書きの数をランダムに対応させたいとき、配列を使って渡すことも可能です。せっかくですので、配列バージョンも解説します。

(配列で渡すバージョン)
src/component/BulletPoint.tsx

//受け取るPropsの型を定義
type Prpps = {
     title: string;
     itemList: string[]
};

export const BulletPoint = ( { title, itemList } : Props ) => {
//受け取るPropsを括弧の中に記載
  return (
       <h3>{ title }</h3>
            <ul>
                { itemList.map(( item: string ) => {
                    return <li>{ item }</li>;
                })}
            </ul>
  );
};

渡ってきた配列をmap()を使って、一つずつ取り出すように実装します。
また、中括弧を使うことでマークアップ中に関数も書くことができます。


src/child2/Like.tsx

import { BulletPoint } from '../component/BulletPoint.tsx';

const likeItemList: string[] = [
         "ジョジョの奇妙な冒険(特に2部が好き)", 
         "ディズニー", 
         "数の子", 
         "旅行",
         "手芸",
//アイテム数を増やす
];

export const Like  = () => {
   return (
       <BulletPoint
          title="好きなもの" 
          itemList = { likeItemList }
//{}中括弧で括って中に渡したい変数を入れる
         />
   );
};



src/child3/Dislike.tsx

import { BulletPoint } from '../component/BulletPoint.tsx'

const dislikeItemList: string[] = [
           "しいたけ", 
           "着ぐるみ", 
           "大きな建物や木, 
];

export const Dislike  = () => {
   return (
       <BulletPoint
          title="苦手なもの" 
          itemList = { dislikeItemList }
//{}中括弧で括って中に渡したい変数を入れる
         />
   );
};

配列で値を渡すことによって、値を追加、削除したい場合、共通コンポーネントを編集しなくても、配列を編集するのみで対応可能となります。また、共通コンポーネントを使用する側でPropsに変数を渡すときは、コメント記載にあるように中括弧で括って中に渡したい変数を入れます。
イメージとしては、itemListという名前で、それぞれのコンポーネントでlikeItemList、dislikeItemListの配列を渡すイメージです。ですが、共通コンポーネント内ではあくまで、itemListという名前でPropsが渡ってきます。

動的HTMLの作成

いよいよ最後です。ここでは、動的なHTMLを作成してみます。先ほどのフォルダを少し変えて使用します。名前、好きなもの、苦手なものボタンを作り、各ボタンが押されたら、それに対応する画面(各マークアップのレスポンス)が表示されるようにしてみます。
この機能を実装するには、Stateという機能を用います。このStateの概念に私はすごく苦戦しました。。。ここでは、簡単に紹介します。
Stateとは、その名の通り、状態を意味します。例えば、ユーザーの操作に応じて、値を更新するといった場合、値の更新や保持といった、その変数の状態を管理するのがStateです。
Stateは、値が更新されることにより、そのStateを持っているコンポーネントが再レンダリングされます。(この概念がすごく難しいです。。。)
Stateの詳しい説明は、下記に置いている私のブログにて紹介しておりますので、気になる方は見てみてください。

tech.nri-net.com



このStateですが、一般的にReactのライブラリ内にあるuseStateというものを用いて実装します。

(useStateの使い方)

//reactからuseStateをimportしてくる
import { useState } from 'react';
const [index, setIndex] = useState("あ");

//State更新する
setIndex("い"); //indexが「い」に更新される

indexは、状態管理される変数で、setIndexは、セッター関数(変数を更新する関数)です。Javaのように、index="い"で、値は更新できないので、その点注意してください。
では、これを踏まえて、ボタンによって表示画面を切り替える動的なHTMLを作成してみましょう。

【ここで実施すること】

・ 各項目の表示を切り替えるボタンとその処理を実装するIntroduceSwich.tsxを作成する
・ ボタンの実装は、共通コンポーネントとして新たにButton.tsxを作成し、それを使ってボタンを実装する)
・ 表示させる項目をStateで管理する(Parents.tsx内で)

【フォルダ構成】

src/
 ├ Parents.tsx //修正を加える(Button.tsxを使って、ボタンを作成)
 ├ IntroduceSwitch.tsx //新たに作成(Stateの値を見て返すコンポーネントを切り替える処理実装)
 ├ child1/
  └ Name.tsx
 ├ child2/
  └ Like.tsx
 ├ child3/
  └ Dislike.tsx
 ├ component/
    ├ BulletPoints.tsx
    ├ Button.tsx //新たに作成(ボタンのひな形)



src/component/Button.tsx

//受け取るPropsの型を定義
type Props = {
     btnName: string;
     clickBtn: MouseEventHandler<HTMLInputElement>;
}
;
export const Button = ( { btnName, clickBtn } : Props ) => {
//受け取るPropsを括弧の中に記載
  return (
         <button onClick={ clickBtn }>{ btnName }</button>
//onClickはボタンが押された際に発火する(ボタンが押されたときに走る処理が渡ってきて実行される)
  );
};

ボタンの共通コンポーネントを作成できました。次にこれをParents.tsxで、各項目ごとにボタンを作成する際に使用します。


src/Parents.tsx

import { Button } from './componet/Button.tsx';
import { introduceSwitch } from './introduceSwitch'

export const Parents = () => {

const [introduce, setIntroduce] = useState('name');
//表示するHTMLのStateを定義(初期値は名前)

   return (
        <h1>自己紹介</h1>
        <Button clickBtn={ () => setIntroduce( 'name' )} btnName="名前" />
//名前ボタンがクリックされたら、自己紹介State(introduce)の値を'name'に更新する
        <Button clickBtn={ () => setIntroduce( 'like' )} btnName="好きなもの" />
//好きなものボタンがクリックされたら、自己紹介State(introduce)の値を'like'に更新する
        <Button clickBtn={ () => setIntroduce( 'dislike' )} btnName="苦手なもの" /
//苦手なものボタンがクリックされたら、自己紹介State(introduce)の値を'dislike'に更新する
        <IntroduceSwitch intro={ introduce }/> 
//選択されているHTMLを表示するコンポーネント
   );
};

上記のように実装することで、例えば、名前ボタンがクリックされたら、'name'にStateを更新することで、現在選択されているボタンを識別する変数として使うことができます。
IntroduceSwitchは、コンポーネントを動的に返すためのコンポーネントとなります。コンポーネントを動的に返す実装をするためには、introduceの現在の値をみることで、押されたボタンを識別することができます(例えば、名前ボタンが押されたら、introduceにnameが入るように実装することで、introduceがnameならName.tsxを返すという実装が可能になる)。そのため、IntroduceSwichにPropsとしてintroduceを渡しています。では、IntroduceSwitch.tsxを実装していきましょう。

src/IntroduceSwitch.tsx

import { Name } from './child1/Name.tsx';
import { Like } from './child2/Like.tsx';
import { Dislike } from './child3/Dislike.tsx';

export const IntroduceSwich = ( { intro } : string ) => {
//Propsとしてわたってきた自己紹介State(intro)には、押されたボタンによって違う値が渡ってくる
//そのStateの値によって、返すコンポーネントを切り替える
            switch ( intro ){
                case 'name' :   
                     return <Name />
                case 'like' :
                     return <Like />
                case 'Dislike' :
                     return <dislike />    
            };
};

このようにswitch文を用いて、returnを切り替える形で実装することで、自己紹介Stateintroduceの現在の値によって、返すコンポーネントを変えることができます。
下記で、各ボタン押下時に起こっていることを図に表してみたので、参考にしてください。

図2 名前ボタン押下時のレスポンス
図3 好きなものボタン押下時のレスポンス
図4 苦手なものボタン押下時のレスポンス

おわりに

今回は、Reactの基本中の基本をReact初学者向けに解説してみましたが、いかがでしたでしょうか。少しでもReactへの理解につながったり、興味を持っていただけるきっかけになれたなら、嬉しいです。
私自身、コードの書き方に慣れるまで少し苦戦しましたが、慣れてしまえば、どう実装すればいいのかということが手に取るように分かり、スラスラと書けるようになりました。
また、動きが目に見えるので、コードも追いやすいと思います。開発者ツールを駆使して、動きを追うことができればもう無敵!!!
これであなたもReactについての知識が身についたはず。これを機にReactマスターになりましょう!!
ここまで読んでいただきありがとうございました。では、またどこかで。

執筆者:嘉地 華香
最後の晩餐は絶対数の子。痛風予備軍の新人フロントエンドエンジニア。
ジョジョの推しはジョセフ・ジョースター。幽波紋よりも波紋戦士。