持久化评论

同样地,可以通过类似于用户名持久化的方式对评论列表内容进行持久化,让用户发布的评论在刷新页面以后依然可以存在。修改 src/CommentApp.js

  1. class CommentApp extends Component {
  2. constructor () {
  3. super()
  4. this.state = {
  5. comments: []
  6. }
  7. }
  8. componentWillMount () {
  9. this._loadComments()
  10. }
  11. _loadComments () {
  12. let comments = localStorage.getItem('comments')
  13. if (comments) {
  14. comments = JSON.parse(comments)
  15. this.setState({ comments })
  16. }
  17. }
  18. _saveComments (comments) {
  19. localStorage.setItem('comments', JSON.stringify(comments))
  20. }
  21. handleSubmitComment (comment) {
  22. if (!comment) return
  23. if (!comment.username) return alert('请输入用户名')
  24. if (!comment.content) return alert('请输入评论内容')
  25. const comments = this.state.comments
  26. comments.push(comment)
  27. this.setState({ comments })
  28. this._saveComments(comments)
  29. }
  30. ...

我们增加了 _loadComments_saveComments 分别用于加载和保存评论列表数据。用户每次提交评论都会把评论列表数据保存一次,所以我们在 handleSubmitComment 调用 _saveComments 方法;而在 componentWillMount 中调用 _loadComments 方法,在组件开始挂载的时候把评论列表数据加载出来 setStatethis.state 当中,组件就可以渲染从 LocalStorage 从加载出来的评论列表数据了。

现在发布评论,然后刷新可以看到我们的评论并不会像以前一样消失。非常的不错,持久化评论的功能也完成了。

显示评论发布时间

现在我们给每条评论都加上发布的日期,并且在评论列表项上显示已经发表了多久,例如“1 秒前”、“30分钟前”,并且会每隔 5 秒进行更新。修改 src/CommentInput.js 当用户点击发布按钮的时候,传出去的评论数据带上评论发布的时间戳:

  1. ...
  2. handleSubmit () {
  3. if (this.props.onSubmit) {
  4. this.props.onSubmit({
  5. username: this.state.username,
  6. content: this.state.content,
  7. createdTime: +new Date()
  8. })
  9. }
  10. this.setState({ content: '' })
  11. }
  12. ...

在评论列表项上显示评论,修改 src/comment.js

  1. class Comment extends Component {
  2. static propTypes = {
  3. comment: PropTypes.object.isRequired
  4. }
  5. constructor () {
  6. super()
  7. this.state = { timeString: '' }
  8. }
  9. componentWillMount () {
  10. this._updateTimeString()
  11. }
  12. _updateTimeString () {
  13. const comment = this.props.comment
  14. const duration = (+Date.now() - comment.createdTime) / 1000
  15. this.setState({
  16. timeString: duration > 60
  17. ? `${Math.round(duration / 60)} 分钟前`
  18. : `${Math.round(Math.max(duration, 1))} 秒前`
  19. })
  20. }
  21. render () {
  22. return (
  23. <div className='comment'>
  24. <div className='comment-user'>
  25. <span>{this.props.comment.username} </span>:
  26. </div>
  27. <p>{this.props.comment.content}</p>
  28. <span className='comment-createdtime'>
  29. {this.state.timeString}
  30. </span>
  31. </div>
  32. )
  33. }
  34. }

每个 Comment 组件实例会保存一个 timeString 状态,用于该评论显示发布了多久。_updateTimeString 这个私有方法会根据 props.comment 里面的 createdTime 来更新这个 timeString:计算当前时间和评论发布时间的时间差,如果已经发布 60 秒以上就显示分钟,否则就显示秒。然后 componentWillMount 会在组件挂载阶段调用 _updateTimeString 更新一下这个字符串,render() 方法就把这个显示时间差的字符串渲染到一个 <span> 上。

再看看页面显示:

React.js 小书实战评论功能图片

这时候的时间是不会自动更新的。除非你手动刷新页面,否则永远显示“1 秒前”。我们可以在 componentWillMount 中启动一个定时器,每隔 5 秒调用一下 _updateTimeString,让它去通过 setState 更新 timeString

  1. ...
  2. componentWillMount () {
  3. this._updateTimeString()
  4. this._timer = setInterval(
  5. this._updateTimeString.bind(this),
  6. 5000
  7. )
  8. }
  9. ...

这样就可以做到评论的发布时间自动刷新了,到这里前 4 个需求都已经完成了。


因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。