7
头图

join us!

Mountain" , to provide front-end developers with technical information and a series of basic articles. For a better user experience, please move to our official website novices (160e55f0b532bd https://xhs-rookies.com/ ) to learn and get the latest articles in time.

"Code tailor" , if you are interested in our article or want to make some suggestions, follow Mountain" public account, contact us, you can also watch it on WeChat Our article. Every suggestion or approval is a great encouragement to us!

Practical case (3): Revised version of the message function

We learned some new content this time, and we need to revise the previous version.

Added like function

What if we need to like a comment?

If you pass in a certain attribute to control whether to show likes as you did last time, this is okay.

We abstracted the InputCompoent input box component and the EvaluateCompoent list display component last time. This time we need to add a comment component to complete the like function.

Unnecessary component removal

Last time we InputCompoent input box component and the EvaluateCompoent list display component and placed them in the component folder. We first placed these two components directly in App.js . (For the sake of intuition, let's put these two already abstracted directly in App.js )

We only need to abstract a comment component, add our like function to the last EvaluateCompoent list display component, and we can like each comment in the list.

Therefore, we App.js as follows:

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

Combining comment components

Like function

First of all, we need to consider what functions this component requires.

In addition to the last abstraction:

In addition to the avatar, time, name, and content, we also need a like button. This button will turn red with one click, and the number will increase by one, click again to change the color to gray again, and the number will decrease by one.

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

One span used to store the like icon, and one is used to display the like number.

Data detection

This time we have more data. After more and more data is passed to the component from the outside, how do we judge, or guarantee that the incoming content is correct? (Is it empty?)

We use propType for content detection. If there is an error, we can quickly help us locate the error and make corrections.

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,
}

Final combination

Then we add the previous EvaluateCompoent list display component with the like function, after adding the data detection function, our comment component is complete.

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

Source address

project github address

Direct preview

We recommend using codesanbox to quickly access current actual combat cases online.

CodeSandBox

Preview of the next section

In the next section, we will talk about the use of State in React related information, in-depth understanding of the setState method and some related content. Stay tuned!


小和山的菜鸟们
377 声望2.1k 粉丝

每日进步的菜鸟,分享前端学习手册,和有心学习前端技术的小伙伴们互相探讨,一同成长。