Selaa lähdekoodia

refactor: 完成评论列表的重构

node 6 vuotta sitten
vanhempi
commit
252126f26a

+ 72
- 17
src/App.js Näytä tiedosto

@@ -33,6 +33,7 @@ class App extends Component {
33 33
     this.sCreateComment = this.sCreateComment.bind(this);
34 34
     this.sCreateReply = this.sCreateReply.bind(this);
35 35
     this.sCommentFavor = this.sCommentFavor.bind(this);
36
+    this.sReplyFavor = this.sReplyFavor.bind(this);
36 37
     this.sOssSts = this.sOssSts.bind(this);
37 38
   }
38 39
 
@@ -102,28 +103,34 @@ class App extends Component {
102 103
     axios
103 104
       .get(`${API}/replies?comment_id=${commentId}&page=${page}&limit=${LIMIT}`)
104 105
       .then(response => {
105
-        const { list: replies } = response.data;
106
-        if (!replies) {
106
+        // const { list: replies, total, page } = response.data;
107
+        if (!response.data.list) {
107 108
           message.info("没有更多数据了!");
108 109
         }
109 110
         const list = this.state.list.map(item => {
110 111
           if (item.id === commentId) {
111 112
             if (!item.replies) item.replies = [];
112
-            if (replies) {
113
+            if (response.data.list) {
113 114
               if (page === 1) {
114 115
                 // 如果当前页数为第一页,则清空当前所有的 replies
115 116
                 // 并将获取到的 replies 存放在 state
116
-                item.replies = replies;
117
+                item.replies = response.data.list;
117 118
               } else {
118
-                item.replies = item.replies.concat(replies);
119
+                item.replies = item.replies
120
+                  .filter(o => !o.isTemporary)
121
+                  .concat(response.data.list);
119 122
                 // 如果当前页数非第一页,则合并 replies
120 123
               }
124
+              item.reply_count = response.data.total;
125
+              item.reply_page = response.data.page;
121 126
             } else {
122 127
               item.isNoMoreReply = true;
123 128
             }
124 129
           }
125 130
           return item;
126 131
         });
132
+        console.log("list: ", list);
133
+
127 134
         this.setState({ list });
128 135
       })
129 136
       .catch(error => {
@@ -185,6 +192,8 @@ class App extends Component {
185 192
    * @param {object} data { comment_id, content, [reply_id] }
186 193
    */
187 194
   sCreateReply(data, cb) {
195
+    console.log("list: ", this.state.list);
196
+
188 197
     if (!data.content) return message.error("回复内容不能为空 ");
189 198
     this.handleChangeLoading("sCreateReply", true);
190 199
     const { API } = this.props;
@@ -194,19 +203,23 @@ class App extends Component {
194 203
       withCredentials: true
195 204
     })
196 205
       .then(response => {
197
-        // // 将该条数据插入到 list 中
198
-        // const list = this.state.list.map(item => {
199
-        //   if (item.id === data.comment_id) {
200
-        //     if (!item.replies) item.replies = [];
201
-        //     item.reply_count += 1
202
-        //     item.replies.unshift(response.data);
203
-        //   }
204
-        //   return item;
205
-        // });
206
-        // this.setState({ list });
207
-        this.sGetReply({ commentId: data.comment_id });
208 206
         message.success("回复成功!");
209 207
         if (isFunction(cb)) cb();
208
+        // 将数据写入到 list 中
209
+        // 临时插入
210
+        // 等到获取数据之后,删除临时数据
211
+        const list = this.state.list.map(item => {
212
+          if (item.id === data.comment_id) {
213
+            if (!item.replies) item.replies = [];
214
+            item.replies.push({
215
+              ...response.data,
216
+              isTemporary: true // 临时的数据
217
+            });
218
+            item.reply_count += 1;
219
+          }
220
+          return item;
221
+        });
222
+        this.setState({ list });
210 223
       })
211 224
       .catch(error => {
212 225
         if (error.response && error.response.data && error.response.data.msg) {
@@ -221,7 +234,7 @@ class App extends Component {
221 234
   }
222 235
 
223 236
   /**
224
-   * 点赞/取消点赞
237
+   * 评论 点赞/取消点赞
225 238
    * @param {string} commentId { commentId }
226 239
    * @param {boolean} favored   是否已经点过赞
227 240
    */
@@ -256,6 +269,47 @@ class App extends Component {
256 269
       });
257 270
   }
258 271
 
272
+  /**
273
+   * 回复 点赞/取消点赞
274
+   * @param {string} replyId  replyId
275
+   * @param {string} commentId  commentId
276
+   * @param {boolean} favored   是否已经点过赞
277
+   */
278
+  sReplyFavor(replyId, commentId, favored) {
279
+    this.handleChangeLoading("sReplyFavor", true);
280
+    console.log("replyId, commentId ", replyId, commentId);
281
+
282
+    const { API } = this.props;
283
+    axios(`${API}/replies/${replyId}/favor`, {
284
+      method: favored ? "delete" : "put",
285
+      withCredentials: true
286
+    })
287
+      .then(response => {
288
+        console.log("response: ", response);
289
+
290
+        message.success(favored ? "取消点赞成功!" : "点赞成功!");
291
+        // // 更新 list 中的该项数据的 favored
292
+        // const list = this.state.list.map(item => {
293
+        //   if (item.id === replyId) {
294
+        //     item.favored = !favored;
295
+        //     item.favor_count += favored ? -1 : 1;
296
+        //   }
297
+        //   return item;
298
+        // });
299
+        // this.setState({ list });
300
+      })
301
+      .catch(error => {
302
+        if (error.response && error.response.data && error.response.data.msg) {
303
+          message.error(lang[error.response.data.msg] || ERROR_DEFAULT);
304
+          return;
305
+        }
306
+        message.error(lang[error.message] || ERROR_DEFAULT);
307
+      })
308
+      .finally(() => {
309
+        this.handleChangeLoading("sReplyFavor", false);
310
+      });
311
+  }
312
+
259 313
   /**
260 314
    * 获取 OSS 上传的参数
261 315
    */
@@ -287,6 +341,7 @@ class App extends Component {
287 341
       sCreateComment: this.sCreateComment,
288 342
       sGetComment: this.sGetComment,
289 343
       sCommentFavor: this.sCommentFavor,
344
+      sReplyFavor: this.sReplyFavor,
290 345
       sCreateReply: this.sCreateReply,
291 346
       sGetReply: this.sGetReply,
292 347
       sOssSts: this.sOssSts

+ 4
- 0
src/avatar.js
File diff suppressed because it is too large
Näytä tiedosto


+ 3
- 3
src/components/CommentBox/index.js Näytä tiedosto

@@ -57,7 +57,7 @@ class CommentBox extends Component {
57 57
                   replyId={item.id}
58 58
                   key={item.id}
59 59
                   content={item}
60
-                  type="replyToReply" // 回复的回复
60
+                  action="replyToReply" // 回复的回复
61 61
                 />,
62 62
                 <div className="moreBox" key="show_more_button">
63 63
                   {!isNoMoreReply &&
@@ -85,7 +85,7 @@ class CommentBox extends Component {
85 85
                 replyId={item.id}
86 86
                 key={item.id}
87 87
                 content={item}
88
-                type="reply" // 评论的回复
88
+                action="replyToReply" // 评论的回复
89 89
               />
90 90
             );
91 91
           })}
@@ -105,7 +105,7 @@ class CommentBox extends Component {
105 105
           onShowReply={this.handleToggleReply}
106 106
           showReply={showReply}
107 107
           commentId={content.id}
108
-          action="comment" // 回复
108
+          action="reply" // 评论的回复
109 109
         />
110 110
         {this.renderReplies(
111 111
           content.replies,

+ 9
- 25
src/components/CommentInput/index.js Näytä tiedosto

@@ -12,6 +12,8 @@ class CommentInput extends Component {
12 12
   handleSubmit(value) {
13 13
     console.log("handleSubmit comment input value: ", value);
14 14
     const { action, commentId, replyId, callback } = this.props;
15
+    console.log(" action, commentId, replyId, callback: ", this.props);
16
+
15 17
     if (action === "comment") {
16 18
       this.props.app.sCreateComment({
17 19
         content: value
@@ -42,34 +44,16 @@ class CommentInput extends Component {
42 44
         // 默认使用 CommentInput 的 onSubmit 来提交评论
43 45
         // 但也可以使用 Editor 的 props 来覆盖 onSubmit
44 46
         onSubmit: this.handleSubmit,
45
-        ...child.props
47
+        ...child.props,
48
+        // 如果当前的编辑器不是“评论”,则编辑器高度减小一些
49
+        rows:
50
+          this.props.action === "comment"
51
+            ? child.props.rows
52
+            : child.props.rows - 1
46 53
       });
47 54
     });
48 55
 
49
-    return (
50
-      <div>
51
-        {/* {type === "normal" ? (
52
-          <div>
53
-            <span
54
-              style={{
55
-                border: "1px solid #CECECE",
56
-                color: "#666",
57
-                padding: "2px 3px",
58
-              }}
59
-            >
60
-              回复
61
-            </span>
62
-            <span style={{ marginLeft: "20px", color: "#5198EB" }}>
63
-              口碑
64
-              <span style={{ marginLeft: "20px", color: "#666666" }}>
65
-                (全站挑出毛病或提出合理建议,奖励10到100元红包)
66
-              </span>
67
-            </span>
68
-          </div>
69
-        ) : null} */}
70
-        <div style={{ marginTop: 40 }}>{childrenWithProps}</div>
71
-      </div>
72
-    );
56
+    return <div>{childrenWithProps}</div>;
73 57
   }
74 58
 }
75 59
 

+ 4
- 1
src/components/CommentList/index.js Näytä tiedosto

@@ -24,10 +24,13 @@ class CommentList extends Component {
24 24
       sGetComment
25 25
     } = this.props.app;
26 26
 
27
-    const spinning = Boolean(loading.sGetComment || loading.sCommentFavor);
27
+    const spinning = Boolean(
28
+      loading.sGetComment || loading.sCommentFavor || loading.sReplyFavor
29
+    );
28 30
     return (
29 31
       <div>
30 32
         <Spin spinning={spinning}>
33
+          <div>共{total} 条评论</div>
31 34
           {list.map(item => (
32 35
             <CommentBox content={item} key={item.id} commentId={item.id} />
33 36
           ))}

+ 1
- 1
src/components/ContentItem/index.css Näytä tiedosto

@@ -9,7 +9,7 @@
9 9
   margin-left: 10px;
10 10
 }
11 11
 .box {
12
-  margin: 10px;
12
+  margin: 10px 0;
13 13
   padding: 15px 5px;
14 14
   border-top: 1px solid #eee;
15 15
 }

+ 33
- 28
src/components/ContentItem/index.js Näytä tiedosto

@@ -4,7 +4,7 @@ import { Avatar, Icon } from "antd";
4 4
 import dayjs from "dayjs";
5 5
 import Comment from "../../Comment";
6 6
 import CommentInput from "../CommentInput";
7
-// import Editor from "../Editor";
7
+import avatar from "../../avatar";
8 8
 import { renderContent } from "../../helper";
9 9
 import "./index.css";
10 10
 
@@ -46,15 +46,14 @@ class CommentItem extends Component {
46 46
       onShowReply,
47 47
       app
48 48
     } = this.props;
49
+    console.log("this.props: ", this.props);
49 50
 
50 51
     const { isShowInput } = this.state;
51
-    console.log("isShowInput ", isShowInput);
52 52
 
53
-    const isComment = action === "comment";
54 53
     return (
55 54
       <div className="box">
56 55
         <div className="left">
57
-          <Avatar src={content.user_avatar} size="large" />
56
+          <Avatar src={content.user_avatar || avatar} size="large" />
58 57
         </div>
59 58
         <div className="right">
60 59
           <div className="name">
@@ -75,19 +74,18 @@ class CommentItem extends Component {
75 74
             }}
76 75
           />
77 76
           <div className="bottom">
78
-            {isComment &&
79
-              content.reply_count && (
80
-                <div>
81
-                  <a
82
-                    className="itemLeft"
83
-                    onClick={onShowReply}
84
-                    style={{ userSelect: "none" }}
85
-                  >
86
-                    {content.reply_count} 条回复
87
-                    {showReply ? <Icon type="up" /> : <Icon type="down" />}
88
-                  </a>
89
-                </div>
90
-              )}
77
+            {content.reply_count ? (
78
+              <div>
79
+                <a
80
+                  className="itemLeft"
81
+                  onClick={onShowReply}
82
+                  style={{ userSelect: "none" }}
83
+                >
84
+                  {content.reply_count} 条回复
85
+                  {showReply ? <Icon type="up" /> : <Icon type="down" />}
86
+                </a>
87
+              </div>
88
+            ) : null}
91 89
 
92 90
             <a onClick={this.handleToggleInput} className="itemRight">
93 91
               &nbsp; 回复
@@ -95,7 +93,14 @@ class CommentItem extends Component {
95 93
             <div
96 94
               className="itemRight"
97 95
               style={{ cursor: "pointer" }}
98
-              onClick={() => app.sCommentFavor(content.id, content.favored)}
96
+              onClick={() => {
97
+                if (replyId) {
98
+                  // 如果有 replyId,则说明是评论的回复
99
+                  app.sReplyFavor(content.id, commentId, content.favored);
100
+                  return;
101
+                }
102
+                app.sCommentFavor(content.id, content.favored);
103
+              }}
99 104
             >
100 105
               <Icon
101 106
                 type="like-o"
@@ -104,17 +109,17 @@ class CommentItem extends Component {
104 109
               &nbsp;{content.favor_count}
105 110
             </div>
106 111
           </div>
107
-
108
-          {/* {isShowInput && (
109
-            <CommentInput
110
-              action={action}
111
-              replyId={replyId}
112
-              commentId={commentId}
113
-              callback={this.handleToggleInput}
114
-            />
115
-          )} */}
116
-          {isShowInput && <CommentInput content={app.children} />}
117 112
         </div>
113
+
114
+        {isShowInput && (
115
+          <CommentInput
116
+            content={app.children}
117
+            action={action}
118
+            replyId={replyId}
119
+            commentId={commentId}
120
+            callback={this.handleToggleInput}
121
+          />
122
+        )}
118 123
       </div>
119 124
     );
120 125
   }

+ 23
- 38
src/components/Editor/index.js Näytä tiedosto

@@ -8,18 +8,18 @@ import Emoji from "./Emoji";
8 8
 import "./index.css";
9 9
 
10 10
 const { TextArea } = Input;
11
-// 设置 Editor 组件的默认值
12
-// 不能在 Editor.defaultProps 中设置
13
-// 因为 Editor 在 ComponentInput 中调用
14
-// 在 ComponentInput 中,需要使用 Editor 的 props 覆盖 ComponentInput 传入的 props
15
-const EditorDefaultProps = {
16
-  rows: 5,
17
-  placeholder: "说点什么吧...",
18
-  showEmoji: true,
19
-  showUpload: true,
20
-  submitText: "发表",
21
-  onChange: () => {}
22
-};
11
+// // 设置 Editor 组件的默认值
12
+// // 不能在 Editor.defaultProps 中设置
13
+// // 因为 Editor 在 ComponentInput 中调用
14
+// // 在 ComponentInput 中,需要使用 Editor 的 props 覆盖 ComponentInput 传入的 props
15
+// const EditorDefaultProps = {
16
+//   rows: 5,
17
+//   placeholder: "说点什么吧...",
18
+//   showEmoji: true,
19
+//   showUpload: true,
20
+//   submitText: "发表",
21
+//   onChange: () => {},
22
+// };
23 23
 
24 24
 class Editor extends React.Component {
25 25
   constructor(props) {
@@ -107,34 +107,10 @@ class Editor extends React.Component {
107 107
       });
108 108
     }
109 109
     this.props.onSubmit(value);
110
-
111
-    // const { type, commentId, replyId, handleToggleInput } = this.props;
112
-    // if (type === "normal") {
113
-    //   this.props.app.sCreateComment({
114
-    //     content: value,
115
-    //   });
116
-    // } else if (type === "comment") {
117
-    //   this.props.app.sCreateReply(
118
-    //     {
119
-    //       comment_id: commentId,
120
-    //       content: value,
121
-    //     },
122
-    //     () => handleToggleInput()
123
-    //   );
124
-    // } else if (type === "reply") {
125
-    //   this.props.app.sCreateReply(
126
-    //     {
127
-    //       comment_id: commentId,
128
-    //       content: value,
129
-    //       reply_id: replyId,
130
-    //     },
131
-    //     () => handleToggleInput()
132
-    //   );
133
-    // }
134 110
   }
135 111
 
136 112
   render() {
137
-    const props = { ...EditorDefaultProps, ...this.props };
113
+    // const props = { ...EditorDefaultProps, ...this.props };
138 114
     const {
139 115
       value,
140 116
       onChange,
@@ -148,7 +124,8 @@ class Editor extends React.Component {
148 124
       showEmoji,
149 125
       showUpload,
150 126
       submitText
151
-    } = props;
127
+    } = this.props;
128
+    // console.log("editor: ", this.props);
152 129
 
153 130
     return (
154 131
       <div className="editor">
@@ -248,4 +225,12 @@ Editor.propTypes = {
248 225
   onChange: PropTypes.func
249 226
 };
250 227
 
228
+Editor.defaultProps = {
229
+  rows: 5,
230
+  placeholder: "说点什么吧...",
231
+  showEmoji: true,
232
+  showUpload: true,
233
+  submitText: "发表"
234
+};
235
+
251 236
 export default Editor;

+ 2
- 0
src/constant.js Näytä tiedosto

@@ -11,3 +11,5 @@ export const OSS_LINK = "http://links-comment.oss-cn-beijing.aliyuncs.com";
11 11
 export const MAX_UPLOAD_NUMBER = 4;
12 12
 
13 13
 export const REGEXP = /\[.+?\]/g;
14
+
15
+export const AVATAR = "";