Table of Contents
ReactとReduxを学ぶために、開発環境というかプロジェクトテンプレートをスクラッチから作っている。 (最終的な成果はGitHubに置いた。)
前回はNode.jsとYarnとBabelとwebpackをセットアップした。
(2018/11/21更新)
Reactとは
以前にも同じような事を書いたけど、改めてReactについて書く。 ちょっとコーディングの詳細にも触れながら。
ReactはViewを記述するためのライブラリで、特徴はVirtual DOMとJSX。
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にする必要がある。
関数で定義したコンポーネントをFunction Component、クラスのものをClass Componentと呼ぶ。 (前者は昔はStateless Functional ComponentとかSFCとかFunctional Componentと呼ばれていた。後者はStateful Componentと呼ばれることもあるけど、React Hooksが出た今、Class Componentの方が適切な呼び方だろう。)
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コンポーネントのprops
のname
は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.6.3が入った。
ソース構成
ソースを入れるsrc
ディレクトリの構成は、Qiitaの記事を参考に以下のようにする。
- react-redux-scaffold/
- src/
- actions/
- components/
- containers/
- reducers/
- sagas/
- services/
- index.jsx
- src/
今のところ使うのはindex.jsx
とcomponents
だけ。
index.jsx
は前回書いた通り、webpackが初めにロードするファイル。
components
にはReactのコンポーネントを入れる。
その他のディレクトリについては追って説明する。
Reactコンポーネント作成
最初のReactコンポーネントとして、適当なものを作る。
src/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
で、id
がroot
の要素を取得してReactDOM.render()
に渡しているので、この<div>
要素のなかに全てのWeb UIがレンダリングされることになる。<body>
の最後に<script src="./bundle.js"></script>
を書くこの
<script>
要素により、bundle.jsがWebサーバからダウンロードされて実行される。
以上でReactは一通り。
yarn start
してブラウザでhttp://localhost:3000
にアクセスするとHOGEと表示されるはず。
次回はフォーマッタとリンタを導入する。