本文做者:鬍子大哈
本文原文:http://huziketang.com/books/react/lesson27javascript
轉載請註明出處,保留原文連接以及做者信息css
在線閱讀:http://huziketang.com/books/reacthtml
{%raw%}前端
如今發佈評論,評論不會消失,評論愈來愈多並非什麼好事。因此咱們給評論組件加上刪除評論的功能,這樣就能夠刪除不想要的評論了。修改 src/Comment.js
的 render
方法,新增一個刪除按鈕:java
... render () { const { comment } = this.props return ( <div className='comment'> <div className='comment-user'> <span className='comment-username'> {comment.username} </span>: </div> <p>{comment.content}</p> <span className='comment-createdtime'> {this.state.timeString} </span> <span className='comment-delete'> 刪除 </span> </div> ) } ...
咱們在後面加了一個刪除按鈕,由於 index.css
定義了樣式,因此鼠標放到特定的評論上纔會顯示刪除按鈕,讓用戶體驗好一些。react
咱們知道評論列表數據是放在 CommentApp
當中的,而這個刪除按鈕是在 Comment
當中的,如今咱們要作的事情是用戶點擊某條評論的刪除按鈕,而後在 CommentApp
中把相應的數據刪除。可是 CommentApp
和 Comment
的關係是這樣的:git
Comment
和 CommentApp
之間隔了一個 CommentList
,Comment
沒法直接跟 CommentApp
打交道,只能經過 CommentList
來轉發這種刪除評論的消息。修改 Comment
組件,讓它能夠把刪除的消息傳遞到上一層:github
class Comment extends Component { static propTypes = { comment: PropTypes.object.isRequired, onDeleteComment: PropTypes.func, index: PropTypes.number } ... handleDeleteComment () { if (this.props.onDeleteComment) { this.props.onDeleteComment(this.props.index) } } render () { ... <span onClick={this.handleDeleteComment.bind(this)} className='comment-delete'> 刪除 </span> </div> ) }
如今在使用 Comment
的時候,能夠傳入 onDeleteComment
和 index
兩個參數。index
用來標誌這個評論在列表的下標,這樣點擊刪除按鈕的時候咱們才能知道你點擊的是哪一個評論,才能知道怎麼從列表數據中刪除。用戶點擊刪除會調用 handleDeleteComment
,它會調用從上層傳入的 props. onDeleteComment
函數告知上一層組件刪除的消息,而且把評論下標傳出去。如今修改 src/CommentList.js
讓它把這兩個參數傳進來:安全
class CommentList extends Component { static propTypes = { comments: PropTypes.array, onDeleteComment: PropTypes.func } static defaultProps = { comments: [] } handleDeleteComment (index) { if (this.props.onDeleteComment) { this.props.onDeleteComment(index) } } render() { return ( <div> {this.props.comments.map((comment, i) => <Comment comment={comment} key={i} index={i} onDeleteComment={this.handleDeleteComment.bind(this)} /> )} </div> ) } }
當用戶點擊按鈕的時候,Comment
組件會調用 props.onDeleteComment
,也就是 CommentList
的 handleDeleteComment
方法。而 handleDeleteComment
會調用 CommentList
所接受的配置參數中的 props.onDeleteComment
,而且把下標傳出去。app
也就是說,咱們能夠在 CommentApp
給 CommentList
傳入一個 onDeleteComment
的配置參數來接受這個刪除評論的消息,修改 CommentApp.js
:
... handleDeleteComment (index) { console.log(index) } render() { return ( <div className='wrapper'> <CommentInput onSubmit={this.handleSubmitComment.bind(this)} /> <CommentList comments={this.state.comments} onDeleteComment={this.handleDeleteComment.bind(this)} /> </div> ) } } ...
如今點擊刪除按鈕,能夠在控制檯看到評論對應的下標打印了出來。其實這就是這麼一個過程:CommentList
把下標 index
傳給 Comment
。點擊刪除按鈕的時候,Comment
把 index
傳給了 CommentList
,CommentList
再把它傳給 CommentApp
。如今能夠在 CommentApp
中刪除評論了:
... handleDeleteComment (index) { const comments = this.state.comments comments.splice(index, 1) this.setState({ comments }) this._saveComments(comments) } ...
咱們經過 comments.splice
刪除特定下標的評論,而且經過 setState
從新渲染整個評論列表;固然了,還須要把最新的評論列表數據更新到 LocalStorage 中,因此咱們在刪除、更新之後調用了 _saveComments
方法把數據同步到 LocalStorage 中。
如今就能夠愉快地刪除評論了。可是,你刪除評論之後 5 秒鐘後就會在控制檯中看到報錯了:
這是由於咱們忘了清除評論的定時器,修改 src/Comment.js
,新增生命週期 commentWillUnmount
在評論組件銷燬的時候清除定時器:
... componentWillUnmount () { clearInterval(this._timer) } ...
這纔算完成了第 5 個需求。
用戶在的輸入內容中任何以 `` 包含的內容都會用 <code>
包含起來顯示到頁面上。<code>
這是一個 HTML 結構,須要往頁面動態插入 HTML 結構咱們只能用 dangerouslySetInnerHTML
了,修改 src/Comment.js
,把原來 render()
函數中的:
<p>{comment.content}</p>
修改爲:
<p dangerouslySetInnerHTML={{ __html: this._getProcessedContent(comment.content) }} />
咱們把通過 this._getProcessedContent
處理的評論內容以 HTML 的方式插入到 <p>
元素中,this._getProcessedContent
是這樣實現的:
... _getProcessedContent (content) { return content .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'") .replace(/`([\S\s]+?)`/g, '<code>$1</code>') } ...
看起來很複雜,其實前 5 行是用來處理 HTML 內容轉義的,最後一行是用來插入 <code>
標籤的。若是咱們把用戶輸入的內容所有以 HTML 顯示到頁面上,那麼就會形成跨站腳本攻擊。因此前 5 個 replace
其實是把相似於 <
、>
這種內容替換轉義一下。而最後一行纔是真正實現需求的代碼,把 `` 包含的內容用 <code>
包裹起來。
輸入:
這是代碼塊 `console.log`,這是 <h1>正常內容</h1>。
看看效果:
咱們安全地完成了第 6 個需求。到目前爲止,第二階段的實戰已經所有完成,你能夠在這裏找到完整的代碼。
到這裏第二階段已經所有結束,咱們已經掌握了所有 React.js 實戰須要的入門知識。接下來咱們會學習兩個相對比較高級的 React.js 的概念,而後進入 React-router 和 Redux 的世界,讓它們配合 React.js 來構建更成熟的前端頁面。
{%endraw%}
下一節中咱們將介紹《React.js 小書 Lesson28 - 高階組件(Higher-Order Components)》。