前提
可能な限りES6の記載で説明している(はず
Reactって
- View部のみ担当するライブラリ
- 仮想DOMにより、余計なレンダリングが発生しない
環境
環境作成
公式見ると、create-react-app使いなさいって感じなので入れる。
https://github.com/facebookincubator/create-react-app
npm install -g create-react-app
create-react-app プロジェクト名
ローカルサーバ起動
cd プロジェクト名
npm start
この状態で
http://localhost:3000/
を開くと、
Reactの初回画面が表示される。
ファイル編集用のエディタ(Atom)
①Atomインストール
https://atom.io/
②gitもいれたほうがいい
③日本語化
「file」→「Setting」→「install」→「japanese-menu」インストール
④入れると捗るパッケージ
autocomplete-paths
convert-to-utf8
⑤React用に捗るパッケージ
react
Atom-beautify
JSXを知ろう
JSXって
Reactは、仮想のDOMを駆使して、望む結果を最終的に表示する。
その過程をHTMLっぽく記載できる方法がJSX。
※HTMLではないので注意
特徴としては、
- HTML5のタグはすべてつかえる
- カスタムコンポーネントをタグ名として使える
- JavaScriptに比べて構造がわかりやすい
などがある。
JSXのわかりやすさを知る
例えば、
「h1タグを用意したい」
とき
React.DOM.h1({className: 'question'}, '質問');
<h1 className="question">質問</h1>
ちなみに上記をカスタムコンポーネントとして作成すれば
<App>質問</App>
こんな記述もできるように。
JSXとHTMLの違い
①JSX独自の属性がある
key、ref、dangeroslySetInnerHTML
②使えない属性もある
class、forは、JavaScriptでも使われるため、属性として使用できない。
以下のように置き換えて使うこと。
HTMLの場合 | JSXの場合 |
---|---|
class | className |
for | htmlFor |
属性値にオブジェクトを渡す
プロパティ名がキャメルケースのオブジェクトを属性値として
渡すことが可能。
var styles = {
borderStyle: "#999",
borderThickness: "1px"
};
〜
/* JSX部 */
<div style={styles}>・・・</div>
/* JSX部 */
コンポーネントを知ろう
コンポーネント?
個人的なイメージで説明すると、
- JSXで表現されたタグ
- 親タグとその子孫タグ
がコンポーネント。
これも
<div></div>
これも
<div><h1>title</h1></div>
1コンポーネントとしての扱い。
カスタムコンポーネント
状況に応じて表示を変える自作のタグ。
実態はJavaScriptのコード。
下記は広義でコンポーネント、狭義だとカスタムコンポーネント。
<Custom></Custom>
コンポーネントでなにするの?
カスタムコンポーネント内のJSXで、
更に別のカスタムコンポーネントを表示。
そのカスタムコンポーネント内のJSXで、またカスタムコンポーネント・・・
といったことを繰り返して、Reactとしての画面描画を行う。
コンポーネント例
create-react-appで作成したプロジェクトを
もうちょっと簡易にした例を参考に、流れを把握しよう。
関係者
./ | |
---|---|
public/ | index.html |
src/ | index.js |
App.js |
//必須
import React, { Component } from 'react';
//Appクラス = Appコンポーネント(カスタムタグ)
class App extends Component {
render() {
return (
//returnの中にJSXを記載
<div className="driver">
<h2>質問</h2>
</div>
);
}
}
//他の場所で読み込んで使えるようにexport
export default App;
//必須
import React from 'react';
import ReactDOM from 'react-dom';
//コンポーネント読み込み
import App from './App';
//(id="root"のところに)描画
ReactDOM.render(
<App />,
document.getElementById('root')
);
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>React App</title>
</head>
<body>
/* ↓この中に描画される */
<div id="root"></div>
</body>
</html>
動的な値を埋め込める
波括弧で変数をJSXの中に埋め込んだりできる。
class App extends Component {
render() {
var text = '質問';
return (
<div className="driver">
<h2>{text}</h2>
</div>
);
}
}
子ノードの受け取り方
<App>質問</App>
こんなJSXがあったとして、
Appコンポーネントでは、その子ノード(ここでは質問というテキスト)を
「this.props.children」で受け取ることができる。
コンポーネントを使いこなすための追加知識
props
コンポーネントのプロパティのこと。
コンポーネントが自己を表現する時に使えるものといえば
プロパティしか無いですよね。
カスタムコンポーネントは
プロパティをpropsというオブジェクトで参照できるようにして、
その状態を見て、自身の描画を変える。
propsを設定
var hoge = [{text: '質問' }];
~
/* JSX */
<List value={hoge} />
/* JSX */
関数も渡せる。
propsの参照
this.props
で行う。
propsの変更や更新
禁止禁止!
親コンポーネントから受け取ったものを変更するなんて、
過去改変して自己の存在を変えるようなものだぞ・・!
propsのデフォルト値
defaultProps(prototypeプロパティ)で設定する。
class App extends Component {
render() {
//propsの参照
var text = this.props.text;
return (
<div className="driver">
<h2>{text}</h2>
</div>
);
}
}
//prototypeプロパティで設定
App.defaultProps = {text: '質問'};
propsのバリデーション
ES6では、propTypes(prototypeプロパティ)で、
ES6以前は、propTypes(クラス内関数)で、
コンフィグオブジェクトを指定する。
App.propTypes = { num: React.PropTypes.number };
※随時追加
オブジェクト | 説明 |
---|---|
state
コンポーネントの状態を保持するオブジェクト。
stateを子コンポーネントのpropsとして渡せば、
親コンポーネントの今を、子コンポーネントに伝搬させることになるので、
結果として、画面の(再)描画が行える。
---------------- --------------------------------
|俺今、こんな状況 | |じゃあ俺コレ使って、自分の表示するわ |
- ------------- ----- --------------------------
V V
(親)つ (state | props) ⊂(子)
stateの初期化
ES6では、constructor(クラス内関数、後述)で、
ES6以前は、getInitialStateで行う。
constructor(props) {
//必須
super(props);
//初期化
this.state = {title: 'list'};
}
stateの参照
this.state
stateの変更
this.setState({key: value})
で行う。
状態の変更が発生するので、再描画(render関数)が行われる。
setStateで変更しないと、画面に反映されないということでもあるので、
直接stateをいじるなんてことはしないこと。
イベントハンドラ
コンポーネントに、イベントハンドラを指定できるが、
少しだけ特殊な仕様がある。
記載の流れ
class App extends Component {
//①イベントハンドラ用関数を定義
eClick(event) {
//処理
}
render() {
return (
<div className="driver">
/* ②イベント紐付け */
<input type="button" onClick={this.eClick.bind(this)} value="1" />
</div>
);
}
}
eventについて
イベントハンドラ内で、その発火元の情報を受け取りたい場合、
eventを第1引数でうけとると、そこから抽出が可能。
console.log(event.target.value); //1
bind(this)
ES6以降で、イベントハンドラ内でthis(コンポーネント)を使いたい場合、
constructorかJSX内でthisをbindしないといけない。
<input type="button" onClick={this.eClick.bind(this)} value="1" />
constructor(props) {
super(props);
this.eClick = this.eClick.bind(this);
}
コンポーネントのライフサイクル
コンポーネントからコンポーネントを呼ぶような作りになってくると、
コンポーネント内のライフサイクルも重要になってくる。
ライフサイクルは、
コンポーネント内で規定の関数、prototypeプロパティで実装してあげると、
所定のタイミングで呼ばれる。
描画まで
動作タイミング | 呼ばれる関数等 | 主な使用目的 |
---|---|---|
初回描画時のみ 初期処理前 |
defaultProps | propsのデフォ値設定。 ES6の場合、prototypeプロパティによる定義で実装。 ※ES6以前の場合、getDefaultProps。 |
初期処理 | constructor(props) | stateの初期化。super(props); を記載しなければならない。このタイミングでthis.propsが使えるようになる。 ※ES6以前の場合、getInitialState。 |
描画直前 | componentWillMount | |
render() | 省略不可。仮想Domの作成。 | |
描画後 | componentDidMount | DOMの操作。 |
描画中
動作タイミング | 呼ばれる関数等 | 主な使用目的 |
---|---|---|
props変更時 | componentWillRecieveProps | stateの変更など。 |
props、state変更時 | shouldComponentUpdate | falseを返すことで、以降の処理をスキップできる。 |
描画直前 | componentWillUpdate | |
render() | ||
描画後 | componentDidUpdate | DOMの操作。 |
コンポーネント破棄
動作タイミング | 呼ばれる関数等 | 主な使用目的 |
---|---|---|
componentWillUnmount |
図示している方がいらっしゃるのでこれがわかりやすいかも。
React component ライフサイクル図