@samitouri / QOS-React / commits / 3812b95450

[docs] Use controlled components for tutorial

Tay Yang Shun committed Nov 18, 2015 at 14:43 UTC 3812b95450fac28fb7c17d9cc57ba2edf9170aac
1 file changed +103 -29
docs/docs/tutorial.md
+103 -29
@@ -492,28 +492,91 @@ var CommentForm = React.createClass({
492 });
493 ```
494
495 -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.
495 +#### Controlled components
496 +
497 +With the traditional DOM, `input` elements are rendered and the browser manages the state (its rendered value). As a result, the state of the actual DOM will differ from that of the component. This is not ideal as the state of the view will differ from that of the component. In React, components should always represent the state of the view and not only at the point of initialization.
498 +
499 +Hence, we will be using `this.state` to save the user's input as it is entered. We define an initial `state` with two properties `author` and `text` and set them to be empty strings. In our `<input>` elements, we set the `value` prop to reflect the `state` of the component and attach `onChange` handlers to them. These `<input>` elements with a `value` set are called controlled components. Read more about controlled components on the [Forms article](/react/docs/forms.html#controlled-components).
500
497 -```javascript{3-14,16-19}
501 +```javascript{3-11,15-26}
502 // tutorial16.js
503 var CommentForm = React.createClass({
504 + getInitialState: function() {
505 + return {author: '', text: ''};
506 + },
507 + handleAuthorChange: function(e) {
508 + this.setState({author: e.target.value});
509 + },
510 + handleTextChange: function(e) {
511 + this.setState({text: e.target.value});
512 + },
513 + render: function() {
514 + return (
515 + <form className="commentForm">
516 + <input
517 + type="text"
518 + placeholder="Your name"
519 + value={this.state.author}
520 + onChange={this.handleAuthorChange}
521 + />
522 + <input
523 + type="text"
524 + placeholder="Say something..."
525 + value={this.state.text}
526 + onChange={this.handleTextChange}
527 + />
528 + <input type="submit" value="Post" />
529 + </form>
530 + );
531 + }
532 +});
533 +```
534 +
535 +#### Events
536 +
537 +React attaches event handlers to components using a camelCase naming convention. We attach `onChange` handlers to the two `<input>` elements. Now, as the user enters text into the `<input>` fields, the attached `onChange` callbacks are fired and the `state` of the component is modified. Subsequently, the rendered value of the `input` element will be updated to reflect the current component `state`.
538 +
539 +#### Submitting the form
540 +
541 +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.
542 +
543 +```javascript{12-21,24}
544 +// tutorial17.js
545 +var CommentForm = React.createClass({
546 + getInitialState: function() {
547 + return {author: '', text: ''};
548 + },
549 + handleAuthorChange: function(e) {
550 + this.setState({author: e.target.value});
551 + },
552 + handleTextChange: function(e) {
553 + this.setState({text: e.target.value});
554 + },
555 handleSubmit: function(e) {
556 e.preventDefault();
502 - var author = this.refs.author.value.trim();
503 - var text = this.refs.text.value.trim();
557 + var author = this.state.author.trim();
558 + var text = this.state.text.trim();
559 if (!text || !author) {
560 return;
561 }
562 // TODO: send request to the server
508 - this.refs.author.value = '';
509 - this.refs.text.value = '';
510 - return;
563 + this.setState({author: '', text: ''});
564 },
565 render: function() {
566 return (
567 <form className="commentForm" onSubmit={this.handleSubmit}>
515 - <input type="text" placeholder="Your name" ref="author" />
516 - <input type="text" placeholder="Say something..." ref="text" />
568 + <input
569 + type="text"
570 + placeholder="Your name"
571 + value={this.state.author}
572 + onChange={this.handleAuthorChange}
573 + />
574 + <input
575 + type="text"
576 + placeholder="Say something..."
577 + value={this.state.text}
578 + onChange={this.handleTextChange}
579 + />
580 <input type="submit" value="Post" />
581 </form>
582 );
@@ -521,24 +584,18 @@ var CommentForm = React.createClass({
584 });
585 ```
586
524 -##### Events
525 -
526 -React attaches event handlers to components using a camelCase naming convention. We attach an `onSubmit` handler to the form that clears the form fields when the form is submitted with valid input.
587 +We attach an `onSubmit` handler to the form that clears the form fields when the form is submitted with valid input.
588
589 Call `preventDefault()` on the event to prevent the browser's default action of submitting the form.
590
530 -##### Refs
531 -
532 -We use the `ref` attribute to assign a name to a child component and `this.refs` to reference the DOM node.
533 -
534 -##### Callbacks as props
591 +#### Callbacks as props
592
593 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 `CommentBox` since `CommentBox` owns the state that represents the list of comments.
594
595 We need to pass data from the child component back up to its parent. We do this in our parent's `render` method by passing a new callback (`handleCommentSubmit`) into the child, binding it to the child's `onCommentSubmit` event. Whenever the event is triggered, the callback will be invoked:
596
597 ```javascript{16-18,31}
541 -// tutorial17.js
598 +// tutorial18.js
599 var CommentBox = React.createClass({
600 loadCommentsFromServer: function() {
601 $.ajax({
@@ -577,26 +634,43 @@ var CommentBox = React.createClass({
634
635 Let's call the callback from the `CommentForm` when the user submits the form:
636
580 -```javascript{10}
581 -// tutorial18.js
637 +```javascript{19}
638 +// tutorial19.js
639 var CommentForm = React.createClass({
640 + getInitialState: function() {
641 + return {author: '', text: ''};
642 + },
643 + handleAuthorChange: function(e) {
644 + this.setState({author: e.target.value});
645 + },
646 + handleTextChange: function(e) {
647 + this.setState({text: e.target.value});
648 + },
649 handleSubmit: function(e) {
650 e.preventDefault();
585 - var author = this.refs.author.value.trim();
586 - var text = this.refs.text.value.trim();
651 + var author = this.state.author.trim();
652 + var text = this.state.text.trim();
653 if (!text || !author) {
654 return;
655 }
656 this.props.onCommentSubmit({author: author, text: text});
591 - this.refs.author.value = '';
592 - this.refs.text.value = '';
593 - return;
657 + this.setState({author: '', text: ''});
658 },
659 render: function() {
660 return (
661 <form className="commentForm" onSubmit={this.handleSubmit}>
598 - <input type="text" placeholder="Your name" ref="author" />
599 - <input type="text" placeholder="Say something..." ref="text" />
662 + <input
663 + type="text"
664 + placeholder="Your name"
665 + value={this.state.author}
666 + onChange={this.handleAuthorChange}
667 + />
668 + <input
669 + type="text"
670 + placeholder="Say something..."
671 + value={this.state.text}
672 + onChange={this.handleTextChange}
673 + />
674 <input type="submit" value="Post" />
675 </form>
676 );
@@ -607,7 +681,7 @@ var CommentForm = React.createClass({
681 Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:
682
683 ```javascript{17-28}
610 -// tutorial19.js
684 +// tutorial20.js
685 var CommentBox = React.createClass({
686 loadCommentsFromServer: function() {
687 $.ajax({
@@ -660,7 +734,7 @@ var CommentBox = React.createClass({
734 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.
735
736 ```javascript{17-23}
663 -// tutorial20.js
737 +// tutorial21.js
738 var CommentBox = React.createClass({
739 loadCommentsFromServer: function() {
740 $.ajax({