Переглянути джерело

L4.1 React events, refs, event handling.

Frederic G. MARAND 8 роки тому
батько
коміт
5e14f24e98
2 змінених файлів з 61 додано та 7 видалено
  1. 5 0
      comments.css
  2. 56 7
      src/comments.js

+ 5 - 0
comments.css

@@ -16,6 +16,11 @@ body {
   text-transform: uppercase;
 }
 
+.comment-box .comment-form-fields>*,
+.comment-box .comment-form-actions {
+  display: block;
+}
+
 .comment-count,
 .comment-footer-delete {
   background-color: #639ca1;

+ 56 - 7
src/comments.js

@@ -8,16 +8,19 @@ State
 - direct reads, write through setState()
 - declare initial state in constructo()
 
+Refs:
+- are called by React during render()
+- (foo) => { this._bar = foo; ) translates to function(foo) { this._bar = foo; }.bind(this);
+
+Events:
+- React events are "synthetic" events, masking the browser behaviour differences
+- https://facebook.github.io/react/docs/events.html
+
 JSX:
 - "className", not "class"
 - knows how to render an array of JSX elements, not just one.
  */
 
-const commentList = [
-  { id: 1, author: "Morgan McCircuit", body: "great picture!" },
-  { id: 2, author: "Bending Bender", body: "Excellent stuff" }
-];
-
 class Comment extends React.Component {
   render() {
     return (
@@ -36,16 +39,61 @@ class Comment extends React.Component {
   }
 }
 
+class CommentForm extends React.Component {
+  _handleSubmit(event) {
+    // Prevent the page from reloading.
+    event.preventDefault();
+    // this._author/this._body are populated by refs in JSX
+    let author = this._author;
+    let body = this._body;
+    // Since they are elements, we need to take their ".value".
+    this.props.addComment(author.value, body.value);
+    // addComment is called on this.props, meaning it is passed by component parent.
+  }
+
+  render() {
+    return (
+      <form className="comment-form" onSubmit={this._handleSubmit.bind(this)}>
+        <label>Join the discussion</label>
+        <div className="comment-form-fields">
+          <input placeholder="Name:"
+            ref={(input) => { this._author = input; } } /* "this" is CommentForm... *//>
+          <textarea placeholder="Comment:"
+            ref={(textarea) => { this._body = textarea; /* ...because of lexical scope */ } } />
+        </div>
+        <div className="comment-form-actions">
+          <button type="submit">Post comment</button>
+        </div>
+      </form>
+    );
+  }
+}
+
 class CommentBox extends React.Component {
   constructor() {
     super();
     this.state = {
-      showComments: false
+      showComments: false,
+      comments: [
+        { id: 1, author: "Morgan McCircuit", body: "great picture!" },
+        { id: 2, author: "Bending Bender", body: "Excellent stuff" }
+      ]
+    };
+  }
+
+  _addComment(author, body) {
+    const comment = {
+      id: this.state.comments.length + 1,
+      author,
+      body
     };
+    // concat(), not push(): push() mutates the data, concat doesn't.
+    // By allocating a new reference, for comments, React detects the change fast.
+    this.setState({comments: this.state.comments.concat([comment])});
   }
 
   _getComments() {
-    return commentList.map((comment) => {
+    return this.state.comments.map((comment) => {
       return (<Comment
         author={comment.author}
         body={comment.body}
@@ -81,6 +129,7 @@ class CommentBox extends React.Component {
       <div className="comment-box">
         <button onClick={this._handleClick.bind(this)}>{buttonText}</button>
         <h4 className="comment-count">{this._getCommentsTitle(comments.length)}</h4>
+        <CommentForm addComment={this._addComment.bind(this)} />
         {commentNodes}
       </div>
     );