React.jsのTutorialを試してみる(3
前回に続いてReact.jsのTutorialを試していきます。思ってたより、長い。
Adding new comments
ようやく投稿フォームの登場です。名前とコメントを入力して送信する仕様みたいです。
CommentFormを変更します。
var CommentForm = React.createClass({
render: function() {
return (
<form className="commentForm">
<input type="text" placeholder="Your name" />
<input type="text" placeholder="Say something..." />
<input type="submit" value="Post" />
</form>
);
}
});
画面表示はこんな感じです。
さらに仕様の追加です。送信したらメッセージをクリアしてリストを更新します。こっから細かいので変更点がわかりづらいと思います。ソースは最後にまとめて載せますが、原文のソースを追いながらのほうがわかりやすいと思います。
まずはメッセージのクリアからです。
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
// TODO: send request to the server
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
}
});
ここで重要なのは3点
- onSubmitのようにcamelCaseのハンドラが用意される
- ref属性で指定した名前でrefsからcomponentを参照できる
- React.findDOMNode(component)でNative DOMにアクセスできる
以上をもとにonSubmitハンドラをトリガーにして、refsとReact.findDOMNodeからinputのDOM elementを取得し、値をクリアします。
つづいてリストの更新ですが、CommentListとCommentFormは兄弟関係にあり親を経由しないとイベントを通知できません。そこでFormにonCommentSubmit
ハンドラを用意し、BoxはそれをトリガーにListを更新します。
まずBox側でFormにハンドラを作成します。
var CommentBox = React.createClass({
...
handleCommentSubmit: function(comment) {
// TODO: submit to the server and refresh the list
},
...
render: function() {
return (
<div className="commentBox">
...
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
つぎにForm側でsubmit時にハンドラを呼び出します。
var CommentForm = React.createClass({
handleSubmit: function(e) {
...
this.props.onCommentSubmit({author: author, text: text});
...
});
つぎにBoxのhandleCommentSubmitに送信処理をajaxで実装します。しかし受信側のURLが現状静的ファイルのため、送信しても見た目上変化はありません。
handleCommentSubmit: function(comment) {
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: comment,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
Optimization: optimistic updates
ここで最初の目標にあげていたUX向上のための処理:サーバからの返答を待たずにリストに反映を追加します。一瞬反映されると思いますが、その後、静的ファイルがレスポンスで帰ってくるので元に戻ると思います。
handleCommentSubmit: function(comment) {
var comments = this.state.data;
var newComments = comments.concat([comment]);
this.setState({data: newComments});
Congrats!
チュートリアルとしてはここで終わりです。やっぱりちゃんと動かしたいので、用意されたソースを使ってサーバサイドも動かしたいと思います。下記zipを解凍し、npm install してください。
https://github.com/reactjs/react-tutorial/archive/master.zip
:~/workspace/react/react-tutorial-master (master) $ npm install
[email protected] node_modules/body-parser
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected])
└── [email protected] ([email protected], [email protected])
[email protected] node_modules/express
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected], [email protected])
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected])
入りました。cloud9上で動かす場合
server.jsの42行目を以下のように変更してください。
app.listen(process.env.PORT, process.env.IP);
その後、public/index.htmlを作成したものに置き換えましょう。置き換えなくても動きますけど、置き換えましょう。
最後にnpm start
でサーバを起動させ、ファイルにアクセスします。ブラウザを複数開けば同期しているのがわかると思います。
サーバサイドの処理を詳しく知りたい方はserver.jsをみるといいと思います。
40行くらいで、ファイルに読み書きしているようです。
最終的なindex.htmlを最後に載せておきます。
<!-- index.html -->
<html>
<head>
<title>Hello React</title>
<script src="https://fb.me/react-0.13.1.js"></script>
<script src="https://fb.me/JSXTransformer-0.13.1.js"></script>
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx">
var data = [
{author: "Pete Hunt", text: "This is one comment"},
{author: "Jordan Walke", text: "This is *another* comment"}
];
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
);
}
});
var CommentList = React.createClass({
render: function() {
var commentNodes =
this.props.data.map(function (comment) {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({author: author, text: text});
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
}
});
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
handleCommentSubmit: function(comment) {
var comments = this.state.data;
var newComments = comments.concat([comment]);
this.setState({data: newComments});
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: comment,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
React.render(
<CommentBox url="comments.json" pollInterval={2000} />,
document.getElementById('content')
);
</script>
</body>
</html>
Author And Source
この問題について(React.jsのTutorialを試してみる(3), 我々は、より多くの情報をここで見つけました https://qiita.com/kazusa-qooq/items/d99fc5c86f0907f09d24著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .