React
このサイトについて
Reactの日本語リファレンスです。 Reactの本家サイト(英文) の内容を翻訳して作成していますが、誤訳や誤記があると思いますのでその点についてはご了承ください。 もし、誤訳などの間違いを見つけましたら、 @tomof まで教えていただければ幸いです。
シンプルなコンポーネント
Reactコンポーネントは、入力データを取得し描画するものを返すrender()
メソッドを実装します。
この例ではJSXと呼ばれるXMLライクな文法を使用しています。
コンポーネントに渡される入力データは、
render()
によって、this.props
を介してアクセス可能になります。
JSXは任意であり、Reactを使用するために必須となるものではありません。 "Compiled JS"を参照して、JSXコンパイラによって生成される生のJavaScriptを確認してみてください。
// JSX
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<HelloMessage name="John" />, mountNode);
// Compiled JS
var HelloMessage = React.createClass({displayName: "HelloMessage",
render: function() {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
React.render(React.createElement(HelloMessage, {name: "John"}), mountNode);
ステートフルなコンポーネント
更に入力データ(this.props
を介してアクセスされた)を取得するために、
コンポーネントは内部の状態(ステート)データを保持することが出来ます。
コンポーネントの状態データが変更する際に、
描画されたマークアップはrender()
が再実行される事によって更新されます。
// JSX
var Timer = React.createClass({
getInitialState: function() {
return {secondsElapsed: 0};
},
tick: function() {
this.setState({secondsElapsed: this.state.secondsElapsed + 1});
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
}
});
React.render(<Timer />, mountNode);
// Compiled JS
var Timer = React.createClass({displayName: "Timer",
getInitialState: function() {
return {secondsElapsed: 0};
},
tick: function() {
this.setState({secondsElapsed: this.state.secondsElapsed + 1});
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return (
React.createElement("div", null, "Seconds Elapsed: ", this.state.secondsElapsed)
);
}
});
React.render(React.createElement(Timer, null), mountNode);
アプリケーション
props
とstate
を使用することで、
小さなTodoアプリケーションを作ることが出来ます。
この例では、ユーザーに入力されたテキストだけで無く、
現在の項目のリストもstate
を使用して追跡します。
イベントハンドラは、インライン描画されるように見えますが、
これらはイベントデリゲーションを使用して集められて実装されます。
// JSX
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText, index) {
return <li key={index + itemText}>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
React.render(<TodoApp />, mountNode);
// Compiled JS
var TodoList = React.createClass({displayName: "TodoList",
render: function() {
var createItem = function(itemText, index) {
return React.createElement("li", {key: index + itemText}, itemText);
};
return React.createElement("ul", null, this.props.items.map(createItem));
}
});
var TodoApp = React.createClass({displayName: "TodoApp",
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
React.createElement("div", null,
React.createElement("h3", null, "TODO"),
React.createElement(TodoList, {items: this.state.items}),
React.createElement("form", {onSubmit: this.handleSubmit},
React.createElement("input", {onChange: this.onChange, value: this.state.text}),
React.createElement("button", null, 'Add #' + (this.state.items.length + 1))
)
)
);
}
});
React.render(React.createElement(TodoApp, null), mountNode);
外部プラグインを使用したコンポーネント
Reactは柔軟に他のライブラリとフレームワークと連結することが出来るフックを提供します。 この例では外部マークダウンライブラリであるShowdownを使用して、リアルタイムでテキストエリアの値を変換します。
// JSX
var converter = new Showdown.converter();
var MarkdownEditor = React.createClass({
getInitialState: function() {
return {value: 'Type some *markdown* here!'};
},
handleChange: function() {
this.setState({value: React.findDOMNode(this.refs.textarea).value});
},
render: function() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
ref="textarea"
defaultValue={this.state.value} />
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={{
__html: converter.makeHtml(this.state.value)
}}
/>
</div>
);
}
});
React.render(<MarkdownEditor />, mountNode);
// Compiled JS
var converter = new Showdown.converter();
var MarkdownEditor = React.createClass({displayName: "MarkdownEditor",
getInitialState: function() {
return {value: 'Type some *markdown* here!'};
},
handleChange: function() {
this.setState({value: React.findDOMNode(this.refs.textarea).value});
},
render: function() {
return (
React.createElement("div", {className: "MarkdownEditor"},
React.createElement("h3", null, "Input"),
React.createElement("textarea", {
onChange: this.handleChange,
ref: "textarea",
defaultValue: this.state.value}),
React.createElement("h3", null, "Output"),
React.createElement("div", {
className: "content",
dangerouslySetInnerHTML: {
__html: converter.makeHtml(this.state.value)
}}
)
)
);
}
});
React.render(React.createElement(MarkdownEditor, null), mountNode);