本文做者:胡子大哈
本文原文: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)》。