Wed, Aug 22, 2018

React + Reduxアプリケーションプロジェクトのテンプレートを作る ― その2: React

React + Reduxアプリケーションプロジェクトのテンプレートを作る ― その2: React

ReactReduxを学ぶために、開発環境というかプロジェクトテンプレートをスクラッチから作っている。 (最終的な成果はGitHubに置いた。)

前回はNode.jsとYarnとBabelとwebpackをセットアップした。

Reactとは

以前にも同じような事を書いたけど、改めてReactについて書く。 ちょっとコーディングの詳細にも触れながら。

ReactはViewを記述するためのライブラリで、特徴はVirtual DOMJSX

Virtual DOM

Virtual DOMはDOMを仮想化するもので、JavaScriptからVirtual DOMでUIを記述してやると、それが実DOMに効率的に反映されるようになっている。

JSX

Virtual DOMはJSXというHTMLみたいな言語で記述できる。

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

こんな風に書くと、idがrootであるHTML要素の中に、<h1>Hello, world!</h1>がレンダリングされる。 上記コードの<h1>Hello, world!</h1>の部分がJSX。

コンポーネント

JSXではコンポーネントを定義して新たなタグとして使うことができるので、再利用できるコンポーネントを作って、それらを組み合わせてUIを構築することで、効率的な開発ができる。

import React from 'react';
import ReactDOM from 'react-dom';

// Welcomeコンポーネントの定義
function Welcome() {
  return <h1>Hello, World</h1>;
}

// Welcomeコンポーネントのレンダリング
ReactDOM.render(
  <Welcome />,
  document.getElementById('root')
);

上記コードではコンポーネントをfunctionで定義しているが、アロー関数で書いても全く一緒。

const Welcome = () => (
  <h1>Hello, World</h1>;
);


関数の代わりにclassで定義することもできる。

class Welcome extends React.Component {
  render() {
    return <h1>Hello, World</h1>;
  }
}

関数による定義とclassによる定義はおおむね変わらないが、stateとライフサイクルメソッドを使いたいときはclassにする必要がある。

props

コンポーネントはレンダリングの際にpropsというパラメータを受け取って使うことができるので、上手く設計すれば汎用的なコンポーネントが書ける。

import React from 'react';
import ReactDOM from 'react-dom';

// Welcomeコンポーネントの定義 (props付き)
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// Welcomeコンポーネントのレンダリング (props付き)
ReactDOM.render(
  <Welcome name="Kaitoy" />,
  document.getElementById('root')
);


propsはイミュータブルにしてコンポーネント内で変更しない(i.e. コンポーネントをpureにする)のが定石。

prop-types

prop-typesを使うと、コンポーネントに渡されるpropsに期待する型を定義することができる。

前節で作ったWelcomeコンポーネントのpropsnameはStringオブジェクトを受け取ることを期待するので、prop-typesを以下のように定義する。

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

Welcome.propTypes = {
  name: PropTypes.string.isRequired,
};

こうしておくと、実行時に型チェックが走り、型が合わないとコンソールに警告がでるようになる。

Reactのインストール

上記のコードを実行するためのライブラリを一通りプロジェクトに追加する。

yarn add react react-dom prop-types

Reactはv16.4.1が入った。

ソース構成

ソースを入れるsrcディレクトリの構成は、Qiitaの記事を参考に以下のようにする。

  • react-redux-scaffold/
    • src/
      • actions/
      • components/
      • containers/
      • reducers/
      • sagas/
      • services/
      • index.jsx


今のところ使うのはindex.jsxcomponentsだけ。

index.jsx前回書いた通り、webpackが初めにロードするファイル。

componentsにはReactのコンポーネントを入れる。

その他のディレクトリについては追って説明する。

Reactコンポーネント作成

最初のReactコンポーネントとして、適当なものを作る。

components/App.jsx:

import React from 'react';

const App = () => (
  <div>
    HOGE
  </div>
);

export default App;

で、これをindex.jsxでインポートしてレンダリングしてやる。

src/index.jsx:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

const root = document.getElementById('root');

if (root) {
  ReactDOM.render(
    <App />,
    root,
  );
}

これでyarn buildするとdist/bundle.jsが生成される。

実践的なコンポーネント構成の考え方については、公式のThinking in Reactが参考になる。

HTMLファイル作成

bundle.jsを読み込むHTMLファイルを作る。

HTMLファイルを書くときは、「普通のHTMLの書き方」の1~3章とか、「フロントエンドチェックリスト」のHead、HTML辺りが参考になる。 まあ開発時にしか使わないだろうから実際は適当でいいし、なんならHtmlWebpackPluginで自動生成してもいい。

作るファイルは、webpackの設定に書いた通り、public/index.html

内容は以下。

public/index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>React Redux</title>
    <meta name="description" content="React Redux Scaffold">
  </head>
  <body>
    <div id="root"></div>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <script src="./bundle.js"></script>
  </body>
</html>


ポイントは2点。

  • <body>の最初にid=root<div>を書く

    上で書いたindex.jsxで、idrootの要素を取得してReactDOM.render()に渡しているので、この<div>要素のなかに全てのWeb UIがレンダリングされることになる。

  • <body>の最後に<script src="./bundle.js"></script>を書く

    この<script>要素により、bundle.jsがWebサーバからダウンロードされて実行される。


以上でReactは一通り。

yarn startしてブラウザでhttp://localhost:3000にアクセスするとHOGEと表示されるはず。

次回はフォーマッタとリンタを導入する。