React.js 官方文档翻译2
2015-03-24 17:43
603 查看
Component Properties
Now that we have defined theCommentcomponent, we will want to pass it the author name and comment text. This allows us to reuse the same code for each unique comment. Now let's add some comments within our
CommentList:
组件属性
var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="Pete Hunt">This is one comment</Comment> <Comment author="Jordan Walke">This is *another* comment</Comment> </div> ); } });
Note that we have passed some data from the parent
CommentListcomponent to the child
Commentcomponents. For example, we passed Pete Hunt (via an attribute) and This is one comment (via an XML-like child node) to the first
Comment. As noted above, the
Commentcomponent will access these 'properties' through
this.props.author, and
this.props.children.
Adding Markdown
Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized.First, add the third-party Showdown library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground):
添加markdown
<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>
Next, let's convert the comment text to Markdown and output it:
var converter = new Showdown.converter(); var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {converter.makeHtml(this.props.children.toString())} </div> ); } });
All we're doing here is calling the Showdown library. We need to convert
this.props.childrenfrom React's wrapped text to a raw string that Showdown will understand so we explicitly call
toString().
But there's a problem! Our rendered comments look like this in the browser: "
<p>This is
<em>another
</em>comment
</p>". We want those tags to actually render as HTML.
That's React protecting you from an XSS attack. There's a way to get around it but the framework warns you not to use it:
Hook up the data model
So far we've been inserting the comments directly in the source code. Instead, let's render a blob of JSON data into the comment list. Eventually this will come from the server, but for now, write it in your source:接入data model
var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ];
We need to get this data into
CommentListin a modular way. Modify
CommentBoxand the
React.render()call to pass this data into the
CommentListvia props:
var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.props.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox data={data} />, document.getElementById('content') );
Now that the data is available in the
CommentList, let's render the comments dynamically:
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> ); } });
Fetching from the server
Let's replace the hard-coded data with some dynamic data from the server. We will remove the data prop and replace it with a URL to fetch:React.render( <CommentBox url="comments.json" />, document.getElementById('content') );
This component is different from the prior components because it will have to re-render itself. The component won't have any data until the request from the server comes back, at which point the component may need to render some new comments.
Reactive state
So far, each component has rendered itself once based on its props.propsare immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable state to the component.
this.stateis private to the component and can be changed by calling
this.setState(). When the state is updated, the component re-renders itself.
render()methods are written declaratively as functions of
this.propsand
this.state. The framework guarantees the UI is always consistent with the inputs.
When the server fetches data, we will be changing the comment data we have. Let's add an array of comment data to the
CommentBoxcomponent as its state:
var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });
getInitialState()executes exactly once during the lifecycle of the component and sets up the initial state of the component.
Updating state
When the component is first created, we want to GET some JSON from the server and update the state to reflect the latest data. In a real application this would be a dynamic endpoint, but for this example, we will use a static JSON file to keep things simple:[ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ]
We'll use jQuery to help make an asynchronous request to the server.
Note: because this is becoming an AJAX application you'll need to develop your app using a web server rather than as a file sitting on your file system. As mentioned above, we have provided several servers you can use on GitHub. They provide the functionality you need for the rest of this tutorial.
var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, componentDidMount: 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) }); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });
Here,
componentDidMountis a method called automatically by React when a component is rendered. The key to dynamic updates is the call to
this.setState(). We replace the old array of comments with the new one from the server and the UI automatically updates itself. Because of this reactivity, it is only a minor change to add live updates. We will use simple polling here but you could easily use WebSockets or other technologies.
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) }); }, 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 /> </div> ); } }); React.render( <CommentBox url="comments.json" pollInterval={2000} />, document.getElementById('content') );
Adding new comments
Now it's time to build the form. OurCommentFormcomponent should ask the user for their name and comment text and send a request to the server to save the comment.
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> ); } });
Let's make the form interactive. When the user submits the form, we should clear it, submit a request to the server, and refresh the list of comments. To start, let's listen for the form's submit event and clear it.
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> ); } });
Events
React attaches event handlers to components using a camelCase naming convention. We attach an
onSubmithandler to the form that clears the form fields when the form is submitted with valid input.
Call
preventDefault()on the event to prevent the browser's default action of submitting the form.
Refs
We use the
refattribute to assign a name to a child component and
this.refsto reference the component. We can call
React.findDOMNode(component)on a component to get the native browser DOM element.
Callbacks as props
When a user submits a comment, we will need to refresh the list of comments to include the new one. It makes sense to do all of this logic in
CommentBoxsince
CommentBoxowns the state that represents the list of comments.
We need to pass data from the child component back up to its parent. We do this in our parent's
rendermethod by passing a new callback (
handleCommentSubmit) into the child, binding it to the child's
onCommentSubmitevent. Whenever the event is triggered, the callback will be invoked:
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) { // TODO: submit to the server and refresh the list }, 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> ); } });
Let's call the callback from the
CommentFormwhen the user submits the 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; } 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> ); } });
Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:
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) { $.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> ); } });
Optimization: optimistic updates
Our application is now feature complete but it feels slow to have to wait for the request to complete before your comment appears in the list. We can optimistically add this comment to the list to make the app feel faster.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.js 官方文档翻译3 代码集合
- React.js 官方文档翻译
- 移动端手势库hammerJS 2.0.4官方文档翻译
- React.js 官方文档摘记:表单
- Reactjs入门官方文档(四)【state-and-lifecycle】
- part2 react官方文档笔记09--JSX In Depth
- Reactjs入门官方文档(八)【forms】
- React-navigation 官方文档中文翻译(二) Nesting Navigators
- Reactjs入门官方文档(五)【handling-events】
- React-navigation 官方文档中文翻译(四) intro to Navigators
- React 官方API文档翻译
- 移动端手势库hammerJS 2.0.4官方文档翻译(转)
- 移动端手势库hammerJS 2.0.4官方文档翻译
- Dojo1.11官方教程文档翻译(2.4)Dojo和Node.js
- Reactjs入门官方文档(六)【conditional-rendering】
- Reactjs入门官方文档(一)【jsx】
- 移动端手势库hammerJS 2.0.4官方文档翻译
- Think in React(官方文档)翻译
- Reactjs入门官方文档(九)【lifting-state-up】
- Reactjs入门官方文档(七)【lists-and-keys】