#3 React.js でプロプラ!Vol.2「Border 7」:コンポーネントの実装1

前回は、コンポーネントのインポートとエクスポート、レンダーについて学びました。
そして、App.tsx の実装も行いました。

あわせて読みたい
#2 React.js でプロプラ!Vol.2「Border 7」:コンポーネントのインポートとエクスポート、レンダー 第2回 コンポーネントのインポートとエクスポート、レンダー 前回は、Border7アプリケーションとプログラムの概要についてお話ししました。 https://hakoratory.com/p...

今回は、テキストやトランプのカードを画面に表示するためのコンポーネントを実装します。
具体的には以下のコンポーネントです。

  • Title
  • Card
  • CardBox
  • MessageBox
  • ScoreBoard

いきなりたくさんの実装になりますが、コンポーネントの一つひとつは大きくないので頑張りましょう!

実装後には Jest によるテストを行い、問題なく実装できているかを確認します。

前回の実装がまだの方は先にそちらからご覧ください。
または以下のブランチをクローンしてから、先にお進みください。

git clone -b implemented-vol-2 https://github.com/hakolab/border7.git
目次

今回学ぶこと

props による値の受け渡し

Reactでは、親子関係にあるコンポーネントがあるとき、親コンポーネントから子コンポーネントに値を受け渡すことができます。
その仕組みが props です。

props は HTML の属性と似たような書き方をします。

function ParentComponent() {
  return (
    <ChildComponent
      paramA={“this is propsA”}
      paramB={“this is propsB”}
    >
    </ChildComponent>
  )
}

親コンポーネントから渡された props は、子コンポーネントでは関数の引数として受け取ることができます。
引数 props はオブジェクトです。親コンポーネントから受け取った値は、子コンポーネントに渡す際に指定した名前で受け取ることができます。

function ChildComponent(props) {
  return (
    <div>
      {props.paramA} // “this is propsA”
      {props.paramB} // “this is propsB”
    </div>
  )
}

上記のように、props オブジェクトをまるごと受け取る形でも何ら問題はありませんが、公式ドキュメントでは分割代入で必要な値のみを受け取ることが推奨されています。

function ChildComponent({paramsA, paramsB}) {
  return (
    <div>
      {paramsA} // “this is propsA”
      {paramsB} // “this is propsB”
    </div>
  )
}

children

props の中には React によって予約されているものがあります。
それが children です。

以下のサンプルでは、HasChildrenComponent に children として div要素や文字列を渡しています。

function App() {
  return (
    <Box>
      <HasChildrenComponent>
        <div>children に div 要素を渡します。</div>
      </HasChildrenComponent>
      <HasChildrenComponent>
        {"children に文字列を渡します"}
      </HasChildrenComponent>
    </Box>
  );
}

function HasChildrenComponent({children}) {
  return (
    <div>
      {children}
    </div>
  )
}

MUI の Boxコンポーネント、Typographyコンポーネントを使う

MUI とは

MUI はコンポーネントライブラリと呼ばれるものです。
おしゃれなボタンやチェックボックスなどの部品が Reactコンポーネントとして提供されています。
その他にも、CSS の flexboxgrid などの画面レイアウトの機能をラップして、設定の手助けをしてくれるコンポーネントも含まれています。

今回は以下の二つのコンポーネントの使い方について説明します。

  • Boxコンポーネント
  • Typographyコンポーネント

Boxコンポーネント

Boxコンポーネントは <div> をレンダーするだけのシンプルなコンポーネントで、汎用的なレイアウト機能を提供します。

https://mui.com/system/react-box/

このコンポーネントを使うことで MUI の CSSユーティリティへのアクセスが可能になります1
シンプルながら、MUI の基本的なコンポーネントだと言えるでしょう。

以下は Appコンポーネントに MUI の sxプロパティ というCSSユーティリティを適用した例です。
widthheightなどのお馴染みの CSS 指定ができる他、bgcolorといった MUI が用意したエイリアスを指定することも可能です2

export default function App() {
  return (
    <Box
      className="app"
      sx={{
        width: 100,
        height: 100,
        bgcolor: 'red'
      }}
    >
      <Title />
      <Border7 />
    </Box>
  )
}

Typographyコンポーネント

Boxコンポーネントがレイアウト機能を提供するのに対して、Typographyコンポーネントはテキスト表示機能を提供します。

Google が提唱する Material Design の Type scale に準拠しており、その中で定義されたスタイル(h1, h2, body など)を使用することで一貫性のあるデザインが可能になります。

The Typography component follows the Material Design typographic scale that provides a limited set of type sizes that work well together for a consistent layout.

https://mui.com/material-ui/react-typography/#component

スタイルの指定は variant 属性で行います。
Typographyコンポーネントがレンダーする実際のHTMLタグは、このvariant 属性で指定した値によって変わります。
レンダーするHTMLタグを変更したい場合はcomponent 属性で変更したいHTMLタグを指定することで変更が可能です。

function VariantMapping() {
  return (
    <Box className="app">
        <Typography variant="h1">
          {"<h1>がレンダーされます</h1>"}
        </Typography>
      <Typography variant="h2">
        {"<h2>がレンダーされます</h2>"}
      </Typography>
      <Typography variant="body1">
        {"<p>がレンダーされます</p>"}
      </Typography>
      <Typography variant="body1" component="span">
        {"<span>がレンダーされます</span>"}
      </Typography>
    </Box>
  );
}

実装

ここまでで、props を使用したコンポーネント間の値の受け渡し、MUI の Boxコンポーネントと Typographyコンポーネントの使い方について学びました。
必要な知識が揃いましたので、早速実装に入りましょう。

Title.jsx の実装

src/components/Title.jsx を開いてください。

Titleコンポーネントは Border7アプリケーションのタイトルをレンダーするコンポーネントです。
Titleコンポーネントを実装することで、以下の画像の赤枠の部分が表示されるようになります。

Titleコンポーネントには以下の JsDoc を記載しています。
これが Titleコンポーネントの設計書です。

/**
 * Titleコンポーネント
 * 1. JSX内のコメントで示している箇所に、Boxコンポーネントをレンダーする
 * 2. 各 Boxコンポーネントは以下の仕様に沿ってレンダーする
 *
 * Box1仕様
 *   class="h1-header" を設定する
 *   children に ’Border7' を渡す
 * Box2仕様
 *   class="h2-header" を設定する
 *   children に 'with プロプラ!' を渡す
 *
 * HINT:
 *   class属性はReactの文法に書き換える必要があります
 *   childrenに渡す文字列は src/constants/text.js にまとめて定義しています
 *
 *  Test command
 *  `npm run test components/Title.test.jsx`
 * @returns {JSX.Element} Title
 */

MUI の Boxコンポーネントをレンダーする

設計書の 1. を見てみましょう。

 * 1. JSX内のコメントで示している箇所に、Boxコンポーネントをレンダーする

設計書の指示に従って、Boxコンポーネントをレンダーしてください。

Boxコンポーネントの作り込み

設計書の 2. とその下に続く Boxコンポーネントの仕様を見てみましょう。

* 2. 各 Boxコンポーネントは以下の仕様に沿ってレンダーする
* 
* Box1仕様
*  class="h1-header" を設定する
*   children に ’Border7' を渡す
* Box2仕様
*   class="h2-header" を設定する
*   children に 'with プロプラ!' を渡す
* 
* HINT:
*   class属性はReactの文法に書き換える必要があります
*   childrenに渡す文字列は src/constants/text.js にまとめて定義しています

それぞれの Boxコンポーネントに class属性と children を設定するよう指示されています。
HINT を参考に、設計書の指示に従ってそれぞれの Boxコンポーネント(Box1, Box2)の作り込みをしてください。

テスト

これで Titleコンポーネントの実装は完了です。
以下のコマンドでテストを行い、問題なく実装ができているかを確認してみましょう。

npm run test components/Title.test.jsx

MessageBox.jsx の実装

src/components/MessageBox.jsx を開いてください。

MessageBoxコンポーネントは、Border7アプリケーションで表示される様々なメッセージを表示するためのコンポーネントです。
MessageBoxコンポーネントを実装することで、以下の画像の赤枠の部分が表示されるようになります。

MessageBoxコンポーネントには以下の JsDoc を記載しています。
これが MessageBoxコンポーネントの設計書です。

/**
 * MessageBoxコンポーネント
 * 1. MessageBox関数の引数 message をオブジェクトリテラルで受け取る
 * 2. JSX内のコメントで示している箇所に、MUI の Typographyコンポーネントをレンダーする
 * 3. Typographyコンポーネントは以下の仕様に沿ってレンダーする
 *
 *  variant属性に "h5"、id属性に "message" を設定する
 *  子要素にMessageBox関数の引数 message を渡す
 *
 *  Test command
 *  `npm run test components/MessageBox.test.jsx`
 *
 * @param message メッセージ
 * @returns {JSX.Element} MessageBox
 */

コンポーネントの引数(props)を受け取る

設計書の 1. を見てみましょう。

 * 1. MessageBox関数の引数 message をオブジェクトリテラルで受け取る

引数 message をオブジェクトリテラルで受け取るよう指示されています。
設計書の指示に従って、引数 message をオブジェクトリテラルで受け取ってください。

MUI の Typographyコンポーネントをレンダーする

設計書の 2. を見てみましょう。

 * 2. JSX内のコメントで示している箇所に、MUI の Typographyコンポーネントをレンダーする

設計書の指示に従って、Typographyコンポーネントを実装してください。

Typographyコンポーネントの作り込み

続いて、設計書の 3. に進みましょう。

 * 3. Typographyコンポーネントは以下の仕様に沿ってレンダーする
 *
 *  variant属性に "h5"、id属性に "message" を設定する
 *  子要素にMessageBox関数の引数 message を渡す

variant属性と id属性および props.children の設定が指示されています。
設計書の指示に従って、MessageBoxコンポーネントの作り込みをしてください。

テスト

これで MessageBoxコンポーネントの実装は完了です。
以下のコマンドでテストを行い、問題なく実装ができているかを確認してみましょう。

npm run test components/MessageBox.test.jsx

ScoreBoard.jsx の実装

src/components/ScoreBoard.jsx を開いてください。

ScoreBoardコンポーネントは、Border7ゲームのスコアを表示するためのコンポーネントです。
ScoreBoardコンポーネントを実装することで、以下の画像の赤枠の部分が表示されるようになります。

ScoreBoardコンポーネントには以下の JsDoc を記載しています。
これが ScoreBoardコンポーネントの設計書です。

/**
 * ScoreBoardコンポーネント
 * 1. ScoreBoard関数の引数 score をオブジェクトリテラルで受け取る
 * 2. JSX内のコメントで示している箇所に、MUI の Typographyコンポーネントをレンダーする
 * 3. Typographyコンポーネントは以下の仕様に沿ってレンダーする
 *
 *  variant属性に "h4"、id属性に "score-text" を設定する
 *  子要素に ScoreBoard関数の引数 score を渡す
 *
 *  Test command
 *  `npm run test components/ScoreBoard.test.jsx`
 *
 * @param score スコア
 * @returns {JSX.Element} ScoreBoard
 */

ScoreBoard.jsx の実装は、MessageBox.jsx の実装時の知識があればできる内容になっています。
設計書の指示に従って、ScoreBoard.jsx を実装してください。

テスト

ScoreBoardコンポーネントの実装が完了しましたら、以下のコマンドでテストを行い、問題なく実装ができているかを確認してみましょう。

npm run test components/ScoreBoard.test.jsx

Card.jsx の実装

src/components/Card.jsx を開いてください。

Cardコンポーネントは、トランプのカードを表示するためのコンポーネントです。
Cardコンポーネントを実装することで、以下の画像の赤枠の部分が表示されるようになります。

Cardコンポーネントには以下の JsDoc を記載しています。
これが Cardコンポーネントの設計書です。

/**
 * Cardコンポーネント
 * 1. Card関数の引数 suit, rank をオブジェクトリテラルで受け取る
 * 2. JSX内のコメントで示している箇所に、Card関数の引数 suit, rank を以下の仕様に沿ってレンダーする
 *
 * Card上:
 *   「♠A」と表示されるようにレンダーする
 * Card中:
 *   「♠」と表示されるようにレンダーする
 * Card下:
 *   「♠A」と表示されるようにレンダーする
 *
 *  Test command
 *  `npm run test components/Card.test.jsx`
 *
 * @param suit トランプのマーク
 * @param rank トランプの数字
 * @returns {JSX.Element} Card
 */

コンポーネントの引数(props)を受け取る

設計書の 1. を見てみましょう。

 * 1. Card関数の引数 suit, rank をオブジェクトリテラルで受け取る

引数 suit, rank をオブジェクトリテラルで受け取るよう指示されています。
設計書の指示に従って、引数 suit, rank をオブジェクトリテラルで受け取ってください。

Cardコンポーネントの作り込み

設計書の 2. を見てみましょう。

 * 2. JSX内のコメントで示している箇所に、Card関数の引数 suit, rank を以下の仕様に沿ってレンダーする
 *
 * Card上:
 *   「♠A」と表示されるようにレンダーする
 * Card中:
 *   「♠」と表示されるようにレンダーする
 * Card下:
 *   「♠A」と表示されるようにレンダーする

設計書の 1. で受け取った引数 suit, rank を、JSX内のコメントに従ってレンダーするよう指示されています。
設計書の指示に従って、引数 suit, rank をそれぞれレンダーしてください。

テスト

これで Cardコンポーネントの実装は完了です。
以下のコマンドでテストを行い、問題なく実装ができているかを確認してみましょう。

npm run test components/Card.test.jsx

CardBox.jsx の実装

src/components/CardBox.jsx を開いてください。

CardBoxコンポーネントは、トランプのカードを配置するためのレイアウト機能を提供するコンポーネントです。
Border7アプリケーションではカードを1枚しか表示しないため、実のところあまり意味を持たないコンポーネントとなります。
今後Border7アプリケーションを拡張して複数枚のカードを表示させるとなった場合には、このコンポーネントを拡張することになるでしょう。

CardBoxコンポーネントには以下の JsDoc を記載しています。
これが CardBoxコンポーネントの設計書です。

/**
 * CardBoxコンポーネント
 * 1. CardBox関数の引数 suit, rank をオブジェクトリテラルで受け取る
 * 2. src/components/Card.jsx から Cardコンポーネントをインポートする
 * 3. JSX内のコメントで示している箇所に、Cardコンポーネントをレンダーする
 * 4. Cardコンポーネントに、CardBox関数の引数 suit, rank を渡す
 *
 *  Test command
 *  `npm run test components/CardBox.test.jsx`
 *
 * @param suit カードのマーク
 * @param rank カードの数字
 * @returns {JSX.Element} CardBox
 */

コンポーネントの引数(props)を受け取る

設計書の 1. を見てみましょう。

 * 1. CardBox関数の引数 suit, rank をオブジェクトリテラルで受け取る

引数 suit, rank をオブジェクトリテラルで受け取るよう指示されています。
設計書の指示に従って、引数 suit, rank をオブジェクトリテラルで受け取ってください。

Cardコンポーネントのインポートとレンダー

設計書の 2.3. を見てみましょう。

 * 2. src/components/Card.jsx から Cardコンポーネントをインポートする
 * 3. JSX内のコメントで示している箇所に、Cardコンポーネントをレンダーする

Cardコンポーネントをインポートしてレンダーするよう指示されています。
設計書の指示に従って、Cardコンポーネントをレンダーしてください。

なお、コンポーネントのインポートとレンダーに関しては第2回で詳しく取り上げていますので、こちらも併せてご覧ください。

Cardコンポーネントに props を渡す

設計書の 4. を見てみましょう。

 * 4. Cardコンポーネントに、CardBox関数の引数 suit, rank を渡す

設計書の 2.3. の手順でレンダーした Cardコンポーネントに、CardBox関数の引数 suit と rank を渡すよう指示されています。
設計書の指示に従って、Cardコンポーネントに、CardBox関数の引数 suit と rank を渡してください。

テスト

これで CardBoxコンポーネントの実装は完了です。
以下のコマンドでテストを行い、問題なく実装ができているかを確認してみましょう。

npm run test components/CardBox.test.jsx

まとめ

お疲れ様でした!
以上で今回の実装はすべて完了です。

今回は5つのコンポーネントを実装しました。
同じ知識で実装できるコンポーネントもあったので、そこまで大変ではなかったかと思います。
また、それぞれのコンポーネントは大きくならないように設計しています。このくらいの規模でコンポーネントを作成しておくと、変更もテストも簡単になります。ご自身で実際にコンポーネントを作るときにぜひご参考ください。

props による値の受け渡し

  • 親コンポーネントから子コンポーネントへの値の受け渡しは props を使う
  • 子コンポーネントで props を受け取るときは分割代入で必要なものだけ受け取る
  • props.children を使うことで、JSX の子要素を渡すことができる

MUI の Boxコンポーネント、Typographyコンポーネントを使う

  • MUI は React のコンポーネントライブラリ
  • Boxコンポーネントはレイアウト機能に特化。スタイル指定などを手助けしてくれる
  • Typographyコンポーネントはテキスt機能に特化。一貫性のあるデザインをすることができる
  1. https://mui.com/system/react-box/#using-the-sx-prop ↩︎
  2. bgcolorは CSS のbackground-colorと対応しています。エイリアスとCSSとの対応関係は以下のURLで確認することができます。
    https://mui.com/system/properties/#properties-reference-table ↩︎
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

28歳のときに音楽家からエンジニアに転向。
WEB系のシステム開発(Java, C#, Vue, React など)に携わっています。

自分らしく力を発揮できて、自信を持って生きられる人を増やすための活動をしています。

コメント

コメントする

目次