React - React 组件基础(发表评论案例)

需求分析

  • 渲染评论列表(列表渲染)
  • 没有评论数据时渲染:暂无评论(条件渲染)
  • 获取评论信息,包括评论人和评论内容(受控组件)
  • 发表评论,更新评论列表(setState()

在这里插入图片描述

搭建评论列表的模板

  • 结构
import React from 'react'
import ReactDOM from 'react-dom'

/* 
  评论列表案例

  comments: [
    { id: 1, name: '图图', content: '真不错!!!' },
    { id: 2, name: '一多', content: '+1' },
    { id: 3, name: '一凡', content: '加油加油!' }
  ]
*/

import './index.css'

class App extends React.Component {
  render() {
    return (
      <div className="app">
        <div>
          <input className="user" type="text" placeholder="请输入评论人" />
          <br />
          <textarea
            className="content"
            cols="30"
            rows="10"
            placeholder="请输入评论内容"
          />
          <br />
          <button>发表评论</button>
        </div>

        <div className="no-comment">暂无评论,快去评论吧~</div>
        <ul>
          <li>
            <h3>评论人:多多</h3>
            <p>评论内容:加油!!!</p>
          </li>
        </ul>
      </div>
    )
  }
}

// 渲染组件
ReactDOM.render(<App />, document.getElementById('root'))
  • 样式
.app {
  width: 300px;
  padding: 10px;
  border: 1px solid #999;
}

.user {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 10px;
}

.content {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 10px;
}

.no-comment {
  text-align: center;
  margin-top: 30px;
}

渲染评论列表

  1. 在state中初始化评论列表数据
  state = {
    comments: [
      { id: 1, name: '图图', content: '真不错!!!' },
      { id: 2, name: '一多', content: '+1' },
      { id: 3, name: '一凡', content: '加油加油!' }
    ]
  }
  1. 使用数组的 map 方法遍历 state 中的列表数据
  2. 给每一个被遍历的 li 元素添加 key 属性
  3. render 方法里的 ul 节点下嵌入表达式
{
  this.state.comments.map(item => {
    return (
       <li key={item.id}>
          <h3>{item.name}</h3>
          <p>{item.content}</p>
       </li>
    )
  })
}

渲染暂无评论

  1. 判断列表数据的长度是否为0
  2. 如果为0,则渲染暂无评论
  3. 如果不为0,那么渲染列表数据
  • 在jsx中大量写逻辑会导致很臃肿,所以我们可以把条件渲染的逻辑抽取成一个函数
/**
 * 条件渲染,这里抽取出来了,这样在结构中不会很混乱
 */
renderList(){
  if (this.state.comments.length === 0) {
    return (<div className="no-comment">暂无评论,快去评论吧~</div>)
  } else {
    return (
      <ul> {
        this.state.comments.map(item => {
          return (
            <li key={item.id}>
              <h3>{item.name}</h3>
              <p>{item.content}</p>
            </li>
          )
        })
      }
      </ul>
    )
  }
}
  • renderreturn方法里面调用这个函数即可
render() {
  return (
    <div>
      ...
      {/* 通过条件渲染来判断是否显示暂无评论 */}
      {this.renderList()}
    </div>
  )
}

获取评论信息

  1. 通过受控组件来获取内容
  2. 初始化用户名和用户内容的state
userName: '',
userContent: ''
  1. 在结构中,把表单元素的 valuestate 进行绑定,还需要绑定 name 属性和 onChange 属性
<input className="user" type="text" placeholder="请输入评论人" value={this.state.userName} name="userName" onChange={this.handleForm}/>
<br />
<textarea
  className="content"
  cols="30"
  rows="10"
  placeholder="请输入评论内容"
  value={this.state.userContent}
  name="userContent"
  onChange={this.handleForm}
/>
  1. handleFrom函数中利用setState来让数据保持一致
  handleForm = (e) => {
     this.setState({
       [e.target.name] : e.target.value
     })
  }

发表评论

  1. 给按钮绑定事件
  2. 在事件处理程序中,通过state获取评论信息
  3. 将评论信息添加到state中,利用setState来更新页面
  4. 添加评论前需要判断用户是否输入内容
  5. 添加评论后,需要情况文本框用户输入的值
handleClick = (e) => {
  // 拿到用户输入的内容
  let {userName,userContent} = this.state
  if(userName.trim()==='' || userContent.trim() === ''){
      alert('请输入内容')
      return
  }
  // 利用数组拓展运算符来进行数据的拼接,把用户输入的存放在数组的第一个位置
  let newComments = [{
    id: this.state.comments.length+1,
    name: userName,
    content: userContent
  },...this.state.comments]
  this.setState({
    comments: newComments,
    userName:'',
    userContent: ''
  })
}

综合代码

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'

class App extends React.Component {
  // 初始化状态
  state = {
    comments: [
      { id: 1, name: '图图', content: '真不错!!!' },
      { id: 2, name: '一多', content: '+1' },
      { id: 3, name: '一凡', content: '加油加油!' }
    ],
    // 评论人
    userName: '',
    // 评论内容:
    userContent: ''
  }

  // 渲染评论列表:
  renderList() {
    const { comments } = this.state

    if (comments.length === 0) {
      return <div className="no-comment">暂无评论,快去评论吧~</div>
    }
    return (
      <ul>
        {comments.map(item => (
          <li key={item.id}>
            <h3>评论人:{item.name}</h3>
            <p>评论内容:{item.content}</p>
          </li>
        ))}
      </ul>
    )
  }

  // 处理表单元素值
  handleForm = e => {
    const { name, value } = e.target

    this.setState({
      [name]: value
    })
  }

  // 发表评论:
  addComment = () => {
    const { comments, userName, userContent } = this.state

    // 非空校验
    if (userName.trim() === '' || userContent.trim() === '') {
      alert('请输入评论人和评论内容')
      return
    }

    // 将评论信息添加到state中
    const newComments = [
      {
        id: Math.random(),
        name: userName,
        content: userContent
      },
      ...comments
    ]

    // 文本框的值如何清空? 要清空文本框只需要将其对应的state清空即可
    this.setState({
      comments: newComments,
      userName: '',
      userContent: ''
    })
  }

  render() {
    const { userName, userContent } = this.state

    return (
      <div className="app">
        <div>
          <input
            className="user"
            type="text"
            placeholder="请输入评论人"
            value={userName}
            name="userName"
            onChange={this.handleForm}
          />
          <br />
          <textarea
            className="content"
            cols="30"
            rows="10"
            placeholder="请输入评论内容"
            value={userContent}
            name="userContent"
            onChange={this.handleForm}
          />
          <br />
          <button onClick={this.addComment}>发表评论</button>
        </div>

        {/* 通过条件渲染决定渲染什么内容: */}
        {this.renderList()}
      </div>
    )
  }
}

// 渲染组件
ReactDOM.render(<App />, document.getElementById('root'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡小多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值