React系列实战篇:留言功能(三)

快来加入咱们吧!

"小和山的菜鸟们",为前端开发者提供技术相关资讯以及系列基础文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 ( xhs-rookies.com/ ) 进行学习,及时获取最新文章。css

"Code tailor" ,若是您对咱们文章感兴趣、或是想提一些建议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的联系,您也能够在微信上观看咱们的文章。每个建议或是赞同都是对咱们极大的鼓励!前端

实战案例(三):留言功能改版

咱们此次学了一些新内容,咱们须要将以前的改版。react

新增点赞功能

若是咱们须要对某个评论进行点赞怎么办呢?git

若是按照上次那样子经过某个属性传入控制是否显示点赞,这是能够的。github

咱们上次抽象了 InputCompoent 输入框组件和 EvaluateCompoent 列表展现组件这两个组件,此次咱们须要新增一个 comment 组件来完成点赞功能。web

不须要的组件去除微信

上次咱们将 InputCompoent 输入框组件和 EvaluateCompoent 列表展现组件抽象出来放置于 component 文件夹中,咱们先将这两个组件直接放置于App.js中。(为了直观,咱们先这两个已经抽象好的给直接放置于 App.js 中)markdown

咱们只须要抽象一个comment组件,给上次的EvaluateCompoent列表展现组件加上咱们的点赞功能,每一个列表中的评论咱们均可以进行点赞。oop

所以咱们将首页App.js修改成以下:学习

import React, { PureComponent } from 'react'
import Comment from './comment'
import './App.css'

class App extends PureComponent {
  constructor() {
    super()
    this.state = {
      title: 'Hello React',
      desc: '你知道有这么一个团队吗?他们怀揣梦想,艰苦奋斗,做为一群大学生菜鸟,放弃了平时娱乐的时间,选择一块儿学习,一块儿成长,将平时学习的笔记,心得总结为文章,目的很简单,但愿能够帮助向他们同样的菜鸟们?你想了解更多吗?快搜索微信公众号:小和山的菜鸟们,加入他们吧!',
      comments: [
        {
          headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
          time: new Date(2021, 4, 14, 21, 2, 30),
          nickName: '小菜鸟',
          detail: '这是一个即将推出系列文章的团队,咱们一块儿期待他们的做品吧!',
          liked: true,
          likeNum: 23,
        },
      ],
      text: '',
    }
  }

  render() {
    const { title, desc, comments, text } = this.state
    return (
      <div className="App"> <h2>{title}</h2> <div className="desc">{desc}</div> <div style={{ width: '100%' }}> <p className="commentsTitle">评论</p> {comments.map((item, index) => { return ( <Comment key={item.time.getTime()} changeLike={() => { this.changeLike(index) }} {...item} /> ) })} </div> <div className="newComment"> <div style={{ display: 'flex' }}> <img src="https://xhs-rookies.com/img/rookie-icon.png" className="" alt="" /> <textarea value={text} onChange={(e) => this.changeText(e)} placeholder="请输入评论" /> </div> <div className="submit" onClick={() => { this.addComment() }} > 发表 </div> </div> </div>
    )
  }

  changeText(e) {
    this.setState({ text: e.target.value })
  }

  changeLike(index) {
    let newArray = [...this.state.comments]
    let newItem = { ...newArray[index] }
    if (newItem.liked) {
      newItem.liked = false
      newItem.likeNum -= 1
    } else {
      newItem.liked = true
      newItem.likeNum += 1
    }
    newArray[index] = newItem
    this.setState({
      comments: newArray,
    })
  }

  addComment() {
    if (!this.state.text) {
      alert('请输入留言内容')
      return
    }
    let detail = this.state.text
    this.setState({ text: '' })
    let newComment = {
      headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
      time: new Date(),
      nickName: '小菜鸟',
      detail,
      liked: false,
      likeNum: 0,
    }
    this.setState({
      comments: [newComment, ...this.state.comments],
    })
  }
}

App.propTypes = {}

export default App
复制代码

组合 comment 组件

点赞功能

首先咱们须要考虑这个组件须要什么功能。

除了上次抽象出来的:

须要有头像、时间、名字、内容这几个外,咱们还须要一个点赞按钮,这个按钮点击一下变成红色,而且数字加一,再次点击颜色从新改成灰色,而且数字减一。

<span className={'likeBox ' + (liked ? 'like' : 'unlike')} onClick={() => changeLike()}>
  <span className="icon"> </span>
  <span>{!!likeNum && likeNum}</span>
</span>
复制代码

一个 span 用于存放点赞图标,一个用于显示点赞的数字。

数据检测

此次咱们数据变得更加多了,外面传给该组件的数据愈来愈多以后,咱们如何判断,或是说保证给进来内容是正确的呢?(是否为空?)

咱们采用propType进行内容检测,若是出现错误,能够快速帮咱们定位错误并进行修改。

Comment.propTypes = {
  nickName: PropTypes.string.isRequired,
  time: PropTypes.object.isRequired,
  headPortrait: PropTypes.string.isRequired,
  detail: PropTypes.string.isRequired,
  liked: PropTypes.bool.isRequired,
  likeNum: PropTypes.number.isRequired,
  changeLike: PropTypes.func.isRequired,
}
复制代码

最终组合

那咱们将以前的EvaluateCompoent列表展现组件加上点赞功能,在将数据检测功能添加进去,咱们的 comment 组件就完成了。

import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import './comment.css'

class Comment extends PureComponent {
  render() {
    const { nickName, time, headPortrait, detail, liked, likeNum, changeLike } = this.props
    return (
      <div className="comment"> <div className="info"> <img src={headPortrait} alt="头像" /> <div> <p className="nickname">{nickName}</p> <p className="time">{this.getTime(time)}</p> </div> </div> <div className="detail" style={{ marginBottom: '10px' }}> {detail} </div> <div className="toolBox"> <span className={'likeBox ' + (liked ? 'like' : 'unlike')} onClick={() => changeLike()}> <span className="icon"> </span> <span>{!!likeNum && likeNum}</span> </span> <span className="share icon"> </span> </div> </div>
    )
  }

  getTime(time) {
    const year = time.getFullYear()
    const month = time.getMonth() + 1
    const day = time.getDate()
    const hour = String(time.getHours()).padStart(2, '0')
    const minute = String(time.getMinutes()).padStart(2, '0')
    const second = String(time.getSeconds()).padStart(2, '0')
    return `${year}.${month}.${day} ${hour}:${minute}:${second}`
  }
}

Comment.propTypes = {
  nickName: PropTypes.string.isRequired,
  time: PropTypes.object.isRequired,
  headPortrait: PropTypes.string.isRequired,
  detail: PropTypes.string.isRequired,
  liked: PropTypes.bool.isRequired,
  likeNum: PropTypes.number.isRequired,
  changeLike: PropTypes.func.isRequired,
}

export default Comment
复制代码

源码地址

项目 github 地址

直接预览

咱们建议采用 codesanbox 的形式能够在线快速访问当前实战案例。

CodeSandBox

下节预告

下节中咱们将讲述使用React中State的相关信息,深刻理解 setState 方法以及一些相关内容。敬请期待!

相关文章
相关标签/搜索