この記事ではReact本体の機能をまとめます。とくにstateやprop周りについて重点的に書こうと思います。

環境構築についてはわかりやすく書いてくださってる人がいるのでこちらを参考に。

Qiita - Webpackでイチから作るReact.js開発環境

Reactとは

UIのパーツ(以下Component)を分割、組み立てをするフロントエンドライブラリです。JSXを書いて利用します。

Reactを使うメリットとして

  • 仮想DOMでドキュメントが抽象化できる
  • 状態がまとまる
  • 描画が早い

をあげることができます。

これらのメリットによって開発を早くできます。

Component作成

パーツは Component クラスを継承して作ります。

import React, {Component} from 'react'

class Message extends Component {
	constructor(prop){
		super(prop);
	}
	render(){
		return (
			<p>[{this.props.username}] : {this.props.message}</p>
		);		
	}
}

これを以下のようにして使います。

import ReactDom from 'react-dom'

window.App = {
	render : () => {
		ReactDom.render(
			<Message username="naca_cyan13" message="hello, react!" />,
			document.getElementById('root')
		);
	}
}

Componentの中でComponentを使う

Componentの中でComponentを使うことができます。先程の MessageMessageList で使ってみましょう。 この時props(詳細は後述)でユーザーの情報をリストとして受け取ってそれをもとに Message を使います。

class MessageList extends Component {
	render(){
		var messages = this.props.messages.map(m => 
			<Message username={m.username} message={m.message} />
		);
		return (
			<div>
			{messages}
			</div>
		);
	}
}

※Componentのconstructor()がsuper()だけになるときはconstructor自体を省略できます。

そして以下のように使う。

window.App = {
	render : () => {
		var messages = [
			{"username": "naca_cyan13", "message": "hello, react!"},
			{"username": "naca_cyan13", "message": "warawara"},
			{"username": "ktoahkeii", "message": "yeah~~!"}
		];
		ReactDom.render(
			<MessageList messages={messages} />,
			document.getElementById('root')
		);
	}
}

値を管理する

Componentに値を渡すのはアプリケーションを作る上で重要です。Reactではそれを円滑にするために、propsstateという形でそれを実現しています。それぞれの特徴についてまとめます。

props

propsはComponent作成時に設定される値を管理するものです。使い方は上記に紹介したコードの通りです。 propsに値を設定するときは、要素の属性として<elem propname=propvalue />のように設定します。 propsは作成された後は変更できません。つまりImmutableなComponentを作成するときに使われます。 また、propTypesを使うことによって、propsに設定されるべき値をバリデーションすることができます。

class Message extends Component {
	constructor(prop){
		super(prop);
		this.defaultProps = {
		};
	}
	render(){
		return (
			<p>[{this.props.username}] : {this.props.message}</p>
		);		
	}
}

Message.propTypes = {
	username : React.PropTypes.string.isRequired,
	message: React.PropTypes.string
};
Message.defaultProps = {
	message: ""
};

このようにComponent定義後、クラス変数 propTypesにバリデーション情報を設定します。 この例の場合、 React.propTypes.string が設定されたものは文字列しか受け付けなくなり、isRequiredがついてるものは必ずそこのデータが入っていることが要求されるようになります。 また、Message.defaultPropsで、propsのデフォルト値を設定することができます。

追記: babelの設定にbabel-preset-stage-0を入れることで、外部で代入していたpropTypesなどをstatic変数として記述することができます。

state

stateはComponent作成後に値の変更をしたい時に使います。stateの初期値は一般にコンストラクタで設定します。その後、変更したい場合は、setState()を使います。

setState()で値が変更された場合、そのComponentは再描画されます。jQueryでは、データの書き換えをするたびに反映処理を手で書かないと行けないのですが、Reactでは値がどこで使用されるのかをかくだけでOKになり非常に楽です。

次の例は、「テキストを入力し追加ボタンを押すとテキスト一覧に追加される」という機能を持ったComponentの定義です。

class TextStack extends Component {
	constructor() {
		this.state = {
			texts : []
			inputText : ""
		};
	}
	
	appendText(){
		// 1.state.messageに入力文字列を追加
		this.setState(prev => {messages : prev.texts.concat([this.state.inputText])});
		// 2.次のメッセージ入力のためにフォームを削除
		this.setState({inputText :  ""});
	}
	
	textChange(){
		// テキストが変更される度にステートに反映
		this.setState({inputText : this.value});
	}
	
	render() {
		var texts = this.state.messages.map(x => <p>{x}</p>);
		return (
			<div>
			<p>テキスト入力</p>
			<input type="text" onChange={this.textChange.bind(this)} value={this.state.inputText}></input>
			<button onClick={this.appendText.bind(this)}>メッセージを追加</button>
			<p>追加したテキスト一覧</p>
			{texts}
			</div>
		);
	}		
}

setState()には2種類呼び方があります。 1つは、前のstateを受け取って、次のstateを返す関数を渡す方法です。

this.setState(prev => {messages : prev.texts.concat([this.state.inputText])});

もう一方は、次のstateをそのまま渡す方法です。

this.setState({inputText :  ""});

その他の機能

Reactでは、自分でハンドラを定義してDOMにバインドすることの他に、 さまざまな描画タイミングや更新タイミングでcomponentWillMount()componentWillUpdate()などのメソッドを読んでくれます。

propstateの他に値を受け渡す方法としてcontextがあります。 これは、componentのネストが深くなった時に威力を発揮します。

今後

Reactを学祭アプリの作成に使うので、実際にそれを使ったアプリケーションのソースコードを読んでみたりして、ノウハウを学べたらいいなと思っています。

参考文献