- 作者:胡子大哈
- 原文鏈接: http://huziketang.com/books/react/lesson16
- 轉載請注明出處,保留原文鏈接和作者信息。
接下來的代碼比較順理成章了。修改 CommentList
可以讓它可以顯示評論列表:
// CommentList.js import React, { Component } from 'react' class CommentList extends Component { render() { const comments = [ {username: 'Jerry', content: 'Hello'}, {username: 'Tomy', content: 'World'}, {username: 'Lucy', content: 'Good'} ] return ( <div>{comments.map((comment, i) => { return ( <div key={i}> {comment.username}:{comment.content} </div> ) })}</div> ) } } export default CommentList
這里的代碼沒有什么新鮮的內容,只不過是建立了一個 comments
的數組來存放一些測試數據的內容,方便我們后續測試。然后把 comments
的數據渲染到頁面上,這跟我們之前講解的章節的內容一樣——使用 map 構建一個存放 JSX 的數組。就可以在瀏覽器看到效果:
修改 Comment.js
讓它來負責具體每條評論內容的渲染:
import React, { Component } from 'react' class Comment extends Component { render () { return ( <div className='comment'> <div className='comment-user'> <span>{this.props.comment.username} </span>: </div> <p>{this.props.comment.content}</p> </div> ) } } export default Comment
這個組件可能是我們案例里面最簡單的組件了,它只負責每條評論的具體顯示。你只需要給它的 props
中傳入一個 comment
對象,它就會把該對象中的 username
和 content
渲染到頁面上。
馬上把 Comment
應用到 CommentList
當中,修改 CommentList.js
代碼:
import React, { Component } from 'react' import Comment from './Comment' class CommentList extends Component { render() { const comments = [ {username: 'Jerry', content: 'Hello'}, {username: 'Tomy', content: 'World'}, {username: 'Lucy', content: 'Good'} ] return ( <div> {comments.map((comment, i) => <Comment comment={comment} key={i} />)} </div> ) } } export default CommentList
可以看到測試數據顯示到了頁面上:
之前我們說過 CommentList
的數據應該是由父組件 CommentApp
傳進來的,現在我們刪除測試數據,改成從 props
獲取評論數據:
import React, { Component } from 'react' import Comment from './Comment' class CommentList extends Component { render() { return ( <div> {this.props.comments.map((comment, i) => <Comment comment={comment} key={i} /> )} </div> ) } } export default CommentList
這時候可以看到瀏覽器報錯了:
這是因為CommentApp
使用 CommentList
的時候並沒有傳入 comments
。我們給 CommentList
加上 defaultProps
防止 comments
不傳入的情況:
class CommentList extends Component { static defaultProps = { comments: [] } ...
這時候代碼就不報錯了。但是 CommentInput
給 CommentApp
傳遞的評論數據並沒有傳遞給 CommentList
,所以現在發表評論時沒有反應的。
我們在 CommentApp
的 state
中初始化一個數組,來保存所有的評論數據,並且通過 props
把它傳遞給 CommentList
。修改 CommentApp.js
:
import React, { Component } from 'react' import CommentInput from './CommentInput' import CommentList from './CommentList' class CommentApp extends Component { constructor () { super() this.state = { comments: [] } } handleSubmitComment (comment) { console.log(comment) } render() { return ( <div className='wrapper'> <CommentInput onSubmit={this.handleSubmitComment.bind(this)} /> <CommentList comments={this.state.comments}/> </div> ) } } export default CommentApp
接下來,修改 handleSubmitComment
:每當用戶發布評論的時候,就把評論數據插入 this.state.comments
中,然后通過 setState
把數據更新到頁面上:
...
handleSubmitComment (comment) {
this.state.comments.push(comment) this.setState({ comments: this.state.comments }) } ...
小提示:這里的代碼直接往
state.comments
數組里面插入數據其實違反了 React.js 的state
不可直接修改的原則 。但其實這個原則是為了shouldComponentUpdate
的優化和變化的跟蹤,而這種目的在使用 React-redux 的時候其實會自然而然達到,我們很少直接手動地優化,這時候這個原則就會顯得有點雞肋。所以這里為了降低大家的理解成本就不強制使用這個原則,有興趣的朋友可以參考: Tutorial: Intro To React - React。
現在代碼應該是可以按照需求正常運作了,輸入用戶名和評論內容,然后點擊發布:
為了讓代碼的健壯性更強,給 handleSubmitComment
加入簡單的數據檢查:
...
handleSubmitComment (comment) {
if (!comment) return if (!comment.username) return alert('請輸入用戶名') if (!comment.content) return alert('請輸入評論內容') this.state.comments.push(comment) this.setState({ comments: this.state.comments }) } ...
到這里,我們的第一個實戰案例——評論功能已經完成了!完整的案例代碼可以在這里 comment-app 找到, 在線演示 體驗。
總結
在這個案例里面,我們除了復習了之前所學過的內容以外還學習了新的知識點。包括:
- 實現功能之前先理解、分析需求,划分組件。並且掌握划分組件的基本原則——可復用性、可維護性。
- 受控組件的概念,React.js 中的
<input />
、<textarea />
、<select />
等元素的value
值如果是受到 React.js 的控制,那么就是受控組件。 - 組件之間使用
props
通過父元素傳遞數據的技巧。
當然,在真實的項目當中,這個案例很多地方是可以優化的。包括組件可復用性方面(有沒有發現其實 CommentInput
中有重復的代碼?)、應用的狀態管理方面。但在這里為了給大家總結和演示,實現到這個程度也就足夠了。
到此為止,React.js 小書的第一階段已經結束,你可以利用這些知識點來構建簡單的功能模塊了。但是在實際項目如果要構建比較系統和完善的功能,還需要更多的 React.js 的知識還有關於前端開發的一些認知來協助我們。接下來我們會開啟新的一個階段來學習更多關於 React.js 的知識,以及如何更加靈活和熟練地使用它們。讓我們進入第二階段吧!
因為第三方評論工具有問題,對本章節有任何疑問的朋友可以移步到 React.js 小書的論壇 發帖,我會回答大家的疑問。