はじめに
この記事はReactの実装をしたことがない人、JSというとjQueryくらいしかやったことがない人でも理解出来るような内容です。
Reactをはじめるというとチュートリアルからはじめるのが基本かと思いますが、チュートリアルよりミニマムにReactってどんなの?というものを実際に実装して感じようというのが目的です。
ただし、npm
はインストール済みが前提なのでnpm
の準備は各自お願いします。
この記事ではReactの概念よりも実装を重要視します。なぜReactが良いのか等は他記事に譲らせて頂きます。
Reactを使うとなぜjQueryが要らなくなるのか
なぜ仮想DOMという概念が俺達の魂を震えさせるのか
簡単に説明すると、ReactはVirtual DOM (仮想DOM)という概念がキーポイントになり、それによって設計面、速度面に利点があります。特徴としてコンポーネントbaseのUIライブラリであることが挙げられて、実装する際にはこのコンポーネントについて理解することが重要です。
また、Fluxというアーキテクチャもありますが、今回はReactの基礎の基礎なので触れません。参考までにReduxがおすすめでチュートリアルも参考になりました。
Redux Tutorial
記法はES6
を採用しています。
デモ
今回作成するのは以下のようなデモです。
環境構築
まず環境構築を行います。gaearon/react-hot-boilerplate を使ってセットアップします。
$ git clone git@github.com:gaearon/react-hot-boilerplate.git
$ cd react-hot-boilerplate
$ npm install
$ npm start
ここでhttp://localhost:3000/
にアクセスして 「Hello, world.」が表示されれば成功です。
これで準備は完了です。
さて、とりあえず表示は出来ました。ここからはその仕組みについて少し解説します。
この箇所ははじめはあまり理解できなくても問題はないのでよく分からなければさらっと読み飛ばしても構いません。
webpack
このレポジトリではwebpack
というビルドツールが使われています。
参考までにですが、以下の記事が分かりやすいと思います。
webpack で始めるイマドキのフロントエンド開発
すごくざっくりというと、書いたJSファイル(Reactのコード)をひとつのファイルにいい感じにまとめて出力してくれる
やつです。
設定ファイルは webpack.config.js
に書かれています。
仕組み
注目すべきファイルは以下の4つです。
- webpack.config.js
- index.html
- src/index.js
- src/App.js
まず、src/index.js
は src/App.js
を読み込んでいます。
読み込みは import App from './App';
の部分です。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
使うときはwebpack.config.js
の設定によって そのsrc/index.js
が static/bundle.js
にコンパイルされます。
そのため表示されるファイルの index.html
で、 static/bundle.js
を読み込んでいます。
<!doctype html>
<html>
<head>
<title>Sample App</title>
</head>
<body>
<div id='root'>
</div>
<script src="/static/bundle.js"></script>
</body>
</html>
さて、ここで再度 src/index.js
を見てみます。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.render(<App />, document.getElementById('root'));
の記述があると思いますが、これはid='root'
の要素の中に<App />
という要素を入れ込むという意味です。ここで<App />
は src/App.js
のことを指しています。
つまり、src/App.js
に書いた記述がブラウザ上のページ(index.html
)に反映される状態になっています。
ここでsrc/App.js
を見てみると確かに Hello, world.
の記述がありますね。
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<h1>Hello, world.</h1>
);
}
}
以降の実装では、このsrc/App.js
にコードを書いていくことで実装を行っていきます。
実装
実装のときにポイントとなるのは
- Component
- state
- props
の3点です。
以下の図を見ながら考えてみて下さい。
Twitterの画面を例にしてみます。ツイートのタイムラインがあります。それを親コンポーネントとすると、ひとつひとつのツイートのボックスが子コンポーネントにあたります。そのようにひとつひとつをコンポーネントに見立てていく感覚が大切です。
また、コンポーネントごとの変数を管理をstate
が、コンポーネント間の変数の受け渡しをprops
が担います。
それでは実際に実装していきます。
state
最初はコンポーネントはひとつしかありません。それはHello World
を出力するコンポーネントです。
厳密ではないですが、ひとつひとつのクラスがコンポーネントになっているイメージです。
まず以下のように編集してみましょう。
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
name: 'James'
}
}
render() {
const name = this.state.name;
return (
<h1>Hello, {name}.</h1>
);
}
}
コンポーネント内に変数を用意します。コンポーネント内部の変数はstate
でしたね。まずは初期値を用意しなければなりません。
そのためにconstructor
を使います。constructor
は初期化のための特殊なメソッドですので覚えてしまいましょう。super(props)
の記述はconstructor
をオーバーライドするので書きますが、はじめは決まりごととして覚えて構いません。そして以下のような記述によってstate
を設定することが出来ます。
constructor(props) {
super(props);
this.state = {
name: 'James'
}
}
実際にこれを表示しましょう。this.state.name
のような記述でstate
にアクセス出来ます。また{}
で囲むことで変数を表示することが出来ます。
render() {
const name = this.state.name;
return (
<h1>Hello, {name}.</h1>
);
これで反映されました。
onChange
ここでinput
の入力欄をつくります。
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
name: 'James'
}
}
render() {
const name = this.state.name;
return (
<div>
<h1>Hello, {name}.</h1>
<input
type="text"
value={name}
onChange={ e => {
this.setState({
name: e.target.value
})
}}
/>
</div>
);
}
}
以下のようにinput
の入力欄を作成出来ます。ちなみに一見htmlですがJSX
という記法になります。ほとんどhtmlライクに書けます。
さて注目はonChange
ですがこれはイベントハンドラです。inputの変更を検知して処理が行われます。ここでは文字を変更させたら{}
内の処理が実行します。onClick
等他のものもあるので調べてみると良いかと思います。
また、this.setState
によってstate
の値を変化させています。注意ですが、this.state.name = 'hoge'
のように変更してはいけません。this.setState
を使うことによって画面に変更が反映されます。
ちなみにe.target.value
はe
でeventを受けてinputに入力したvalue値を取っています。
また =>
これはES6のアロー関数を採用しているものなので気になる方は調べて見て下さい。
<input
type="text"
value={name}
onChange={ e => {
this.setState({
name: e.target.value
})
}}
/>
もう一点注意ですが、<h1>
と<input>
を<div>
で囲っています。これはreturn
の中のDOM要素はひとつにしないとエラーになるためです。
以下のように反映されているはずです。
props
機能自体はほぼ出来ましたが、名前表示の部分だけを子のコンポーネントに切り出してみます。
また、state
の初期値を空にしておきます。
import React, { Component } from 'react';
class Name extends Component {
render () {
const name = this.props.name;
return (
<span style={{color: 'red'}}>{name}</span>
);
}
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
}
render() {
const name = this.state.name;
return (
<div>
<h1>Hello, <Name name={name} />.</h1>
<input
type="text"
value={name}
onChange={ e => {
this.setState({
name: e.target.value
})
}}
/>
</div>
);
}
}
子のコンポーネントを以下のように作成しました。ポイントはprops
です。親で指定したprops
(指定の仕方はこの後で)をstate
と同じ要領で呼び出します。これでreturn
の中身を親コンポーネントで表示出来ます。
class Name extends Component {
render () {
const name = this.props.name;
return (
<span style={{color: 'red'}}>{name}</span>
);
}
}
さて親コンポーネントで子コンポーネントの呼出ですが以下のような<Name />
で呼び出せます。<Name name={name} />
のようにプロパティを指定するとpropsとして子コンポーネントに値を引き渡せます。
<h1>Hello, <Name name={name} />.</h1>
以上で以下のように反映されます。
これで完成です!
終わりに
これだけ分かればReactの基礎の基礎は分かったことになると思います。以降チュートリアルをやるなどやってみましょう。
今回採用したES6でのチュートリアルも作成されていました。
ES6版React.jsチュートリアル
また、僕のReact勉強のログとして以下のレポジトリにまとめてあります。(そのため、チュートリアルほぼそのままのやつもあったりです。今度アップデートさせたいと思っています。)
ローカルで起動させると教科書的に使えるかと思うので参考になれば幸いです。
今回の記事の内容の機能もこれの一番最初のデモです。
kuboshizuma/react-practice