クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【React】HTMLコンポーネント化(Reactとメタ言語の比較-1)

Reactの続きです。前回はReact + TypeScript + CSS in JSの開発環境を作りました。今回から以前作ったメタ言語スターターキットの内容をReact環境に移植してみます。まずはHTMLのコンポーネント化から。それではいきましょう!

【目次】

※参考:前回記事
【React】React + TypeScript + CSS in JSの開発環境を作る(Gitエラー対処も) - クモのようにコツコツと

※参考:Reactを習得するためにやったことまとめ
qiita.com

前回のおさらい

React + TypeScript + CSS in JSの開発環境を作る。

https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20210131/20210131150057.jpg

React + TypeScript環境に以前作ったstyled-componentsのCSS in JSをインポートしてみる。TypeScript環境に新たなライブラリ等を追加するには@Typesパッケージが必要なことがわかる。

※参考:【React】styled-componentsでCSS in JSを事始める - クモのようにコツコツと
※参考:【React】React + TypeScript + CSS in JSの開発環境を作る(Gitエラー対処も) - クモのようにコツコツと

Reactとメタ言語(EJS、Sass(SCSS)、TypeScript)を比較したい

以前作ったメタ言語スターターキットを作った。この時はHTMLはEJS、CSSはSass(SCSS)、JSはTypeScriptで構成し、それぞれのフォルダの中でモジュール分割していた。

https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201201/20201201081214.jpg

※参考:【メタ言語】フロントエンド開発スターターキットを作った(EJS、Sass(SCSS)、TypeScript) - クモのようにコツコツと

React + TypeScript + CSS in JS環境ではコンポーネントごとにHTML、CSS、JSの内容が入れる構成になる。同じ内容を作る上でどう変わるかを知りたい。

React + TypeScript + CSS in JS環境にメタ言語スターターキットの内容を移植して比較してみる。

React + TypeScript + CSS in JS環境構築

まずはベースとなるReact + TypeScript + CSS in JS環境の構築。基本は前回と同じ手順。

※参考:【React】React + TypeScript + CSS in JSの開発環境を作る(Gitエラー対処も) - クモのようにコツコツと

まずCreate React AppをTypeScript付きでインストール。アプリ名は「react-from-meta-lang」とする。

$ npx create-react-app react-from-meta-lang --template typescript

「react-from-meta-lang」フォルダができるので移動する。

$ cd react-from-meta-lang

CSS in JSの「styled-components」をインストール

$ npm i --save styled-components

続いて「@types/styled-components」も忘れずにインストール

$ npm i --save @types/styled-components

package.json確認、追加された!

  "dependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.3",
    "@testing-library/user-event": "^12.6.2",
    "@types/jest": "^26.0.20",
    "@types/node": "^12.19.15",
    "@types/react": "^16.14.2",
    "@types/react-dom": "^16.9.10",
    "@types/styled-components": "^5.1.7", // 追加
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "styled-components": "^5.2.1", // 追加
    "typescript": "^4.1.3",
    "web-vitals": "^0.2.4"
  },

前回は@types/styled-componentsを--save-devでインストールしたのでdevDependenciesに入ったが今回は他と同じdependenciesに入った♪

アプリを起動してみる

$ npm start

よし、クルクルしとる♪ f:id:idr_zz:20210202054112j:plain

いったん「Control + C」で閉じる。

HTML部分をコンポーネント化

Webコーディングスターターターキットを移植

メタ言語環境からコンパイル後のコードをベースにした「Webコーディングスターターキット」

https://cdn-ak.f.st-hatena.com/images/fotolife/i/idr_zz/20201201/20201201081646.jpg

コード(GitHub)
※参考:GitHub - ryo-i/web-coding-getting-sterted: HTML/CSS/JSコーディングの最小環境です。

プレビュー(GitHub Pages)
※参考:Webコーディング スターターキット

その中の「index.html」(EJSからコンパイル後の内容)

※参考:web-coding-getting-sterted/index.html at master · ryo-i/web-coding-getting-sterted · GitHub

まずはこの内容を移植していく。

index.html:headタグ打ち替え

まず「public」フォルダにある「index.html」

<head>
  <!-- 中略 -->
  <meta
      name="description"
      content="以前作ったメタ言語スターターキットの内容をReact環境で再現してみる"
    />
    <!-- 中略 -->
    <title>メタ言語とReactの比較</title>
</head>

headタグのtitledescriptionだけ打ち変える

ちなみにReactの仮想DOMがレンダリングされるのは#rootタグ

<div id="root"></div>

ここは変更なし。

index.tsx:Header、Main、Footerを読み込む

次は「src」フォルダの「index.tsx」

インポート部分

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Header from './Header'; // 変更
import Main from './Main'; // 変更
import Footer from './Footer'; // 変更
import reportWebVitals from './reportWebVitals';

HeaderMainFooterコンポーネントをインポート(デフォルトはAppコンポーネントを読み込んでいた)

ReactDOM.render()部分

ReactDOM.render(
  <React.StrictMode>
    <Header />
    <Main />
    <Footer />
  </React.StrictMode>,
  document.getElementById('root')
);

HeaderMainFooterコンポーネントを配置

Header.tsx:headerタグを移植

新規作成したHeader

import React from 'react';

function Header() {
  return (
    <header className="header">
        <h1 className="header__title">メタ言語とReactの比較</h1>
        <p className="header__text">以前作ったメタ言語スターターキットの内容をReact環境で再現してみる</p>
    </header>
  );
}

export default Header;

ここに先ほどの「index.html」のheadタグの内容を移植してみる。

※参考:web-coding-getting-sterted/index.html at master · ryo-i/web-coding-getting-sterted · GitHub

Main.tsx:mainタグを移植

次にMain.tsx(App.tsxを改名したファイル)

import React from 'react';

function Main() {
  return (
    <main>
      <section className="main">
          <h1 className="main__title">タイトルです</h1>
          <p className="main__title">テキストです。テキストです。テキストですったらテキストです。</p>
          <section className="inner">
              <h2 className="inner__title">CSS(文字色)</h2>
              <p className="inner__text">CSSでタイトルの文字色変更。</p>
          </section>
          <section className="inner">
              <h2 className="inner__title">JS(文字列)</h2>
              <p className="inner__text">JSでテキストの文字列追加→「<span className='inner__text--hello'></span>」</p>
          </section>
      </section>
    </main>
  );
}

export default Main;

ここには「index.html」のmainタグの中身を移植している。

※参考:web-coding-getting-sterted/index.html at master · ryo-i/web-coding-getting-sterted · GitHub

Footer.tsx:footerタグを移植

最後に「Footer.tsx」を新規作成

import React from 'react';

function Footer() {
  return (
    <footer className="footer">
        <p className="footer__text">©️ react-from-meta-lang</p>
    </footer>
  );
}

export default Footer;

ブラウザ挙動

この時点でいったんアプリを起動してみると

$ npm start

やた!HTMLページが生成された! f:id:idr_zz:20210202064033j:plain

CSS部分の移植

index.cssを打ち替え

このままでは寂しいのでCSSスタイルを当てる。

「index.tsx」に「index.css」がインポートされているので

import './index.css';

「index.css」の内容を下記に打ち替える。

/***** base *****/
body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  font-size: 14px;
  color: #333;
}

body *, body *:before, body *:after {
  box-sizing: border-box;
}

body a {
  color: #ff0000;
}

/***** block *****/
/* header */
.header {
  width: 100%;
  max-width: 1000px;
  padding: 20px;
  margin: 0 auto;
  text-align: center;
  background: #eee;
  padding: 20px;
}

.header__title {
  font-size: 2em;
}

/* main */
.main {
  width: 100%;
  max-width: 1000px;
  padding: 20px;
  margin: 0 auto;
}

.main__title {
  font-size: 1.5em;
}

/* inner */
.inner__title {
  font-size: 1.25em;
  color: #ff0000;
}

/* footer */
.footer {
  width: 100%;
  max-width: 1000px;
  padding: 20px;
  margin: 0 auto;
  text-align: center;
}

これは「Webコーディングスターターキット」の「style.css」(Sass(SCSS)コンパイル後)の内容

※参考:web-coding-getting-sterted/style.css at master · ryo-i/web-coding-getting-sterted · GitHub

この内容をそのまま移植している。

ブラウザ挙動

ブラウザをリロードすると… f:id:idr_zz:20210202064759j:plain おお、スタイルが当たった!

JS部分の移植

Main.jsにhello.jsをインポート

次にJS部分を移植したい。

「Main.js」で「hello.js」をインポートする。

import React from 'react';
import './hello.js';

最初、index.tsxにインポートしたらDOMとJSの読み込み順の関係でうまく動かなかった。。

hello.jsを作成

「hello.js」を新規作成

const hello = JSON.parse(
    '{"message":{"text":"こんにちは、ふろんとえんど。","selector":".inner__text--hello"}}'
    );
    
    const message = { 
        text: hello.message.text, 
        selector: hello.message.selector 
    };
    
    const text = message.text;
    const selector = message.selector;
    
    document.addEventListener("DOMContentLoaded", () => {
        document.querySelector(selector).innerHTML = text;
        console.log("text-> " + text);
    });

これは「Webコーディングスターターキット」の「script.js」(TypeScriptコンパイル後の改造版)の内容

※参考:https://github.com/ryo-i/web-coding-getting-sterted/blob/master/docs/js/script.js

ブラウザ挙動

ブラウザをリロードすると… f:id:idr_zz:20210202065525j:plain やた!「こんにちは、ふろんとえんど。」の文字が表示された!


ソース(GitHub)※今回のコミットまで

※参考:GitHub - ryo-i/react-from-meta-lang at 8478499fbdd193e07008264f5bd2df0b5f2d7354

プレビュー(GitHub Pages)

※参考:Reactとメタ言語の比較

最後に

ということで、Reactとメタ言語の比較、まずはHTMLをJSXでコンポーネント化することから始めました。

現時点ではCSSとJSはHTMLタグのclass名と紐づいているのでこれまでとあまり変わっていません。これからReactやCSS in JSの機能にさらに組み込んでみたく思います。また、JS部分にはTypeScriptのモジュール分割を再現してみたく。

あとメタ言語環境ではテキスト部分は外部のJSONから読み込んでいますが、今はタグに直書きしています。このテキスト部分もReactの状態管理などに組み込んでいきたく。

道のりは長いですが少しずつ進めていきます。それではまた!


※参考:Reactを習得するためにやったことまとめ
qiita.com