React.js 小书 Lesson15 - 实战分析:评论功能二

React.js 小书 Lesson15 - 实战分析:评论功能(二)

本文作者:胡子大哈
本文原文:http://huziketang.com/books/react/lesson15

转载请注明出处,保留原文链接以及作者信息

在线阅读:http://huziketang.com/books/react

上一节我们构建了基本的代码框架,现在开始完善其他的内容。

处理用户输入

我们从 ComponentInput 组件开始,学习 React.js 是如何处理用户输入的。首先修改 ComponentInput.js,完善 ComponentInputrender 函数中的 HTML 结构:

import React,{ Component } from 'react'

class CommentInput extends Component {
  render () {
    return (
      <div className='comment-input'>
        <div className='comment-field'>
          <span className='comment-field-name'>用户名:</span>
          <div className='comment-field-input'>
            <input />
          </div>
        </div>
        <div className='comment-field'>
          <span className='comment-field-name'>评论内容:</span>
          <div className='comment-field-input'>
            <textarea />
          </div>
        </div>
        <div className='comment-field-button'>
          <button>
            发布
          </button>
        </div>
      </div>
    )
  }
}

export default CommentInput

在浏览器中可以看到 ComponentInput 的结构和样式都已经生效:

因为还没有加入处理逻辑,所以你输入内容,然后点击发布是不会有什么效果的。用户可输入内容一个是用户名(username),一个是评论内容(content),我们在组件的构造函数中初始化一个 state 来保存这两个状态:

...
class CommentInput extends Component {
  constructor () {
    super()
    this.state = {
      username: '',content: ''
    }
  }
  ...
}
...

然后给输入框设置 value 属性,让它们的 value 值等于 this.state 里面相应的值:

...
        <div className='comment-field'>
          <span className='comment-field-name'>用户名:</span>
          <div className='comment-field-input'>
            <input value={this.state.username} />
          </div>
        </div>
        <div className='comment-field'>
          <span className='comment-field-name'>评论内容:</span>
          <div className='comment-field-input'>
            <textarea value={this.state.content} />
          </div>
        </div>
...

可以看到接受用户名输入的 <input /> 和接受用户评论内容的 <textarea />value 值分别由 state.usernamestate.content 控制。这时候你到浏览器里面去输入内容看看,你会发现你什么都输入不了。

这是为什么呢?React.js 认为所有的状态都应该由 React.js 的 state 控制,只要类似于 <input /><textarea /><select /> 这样的输入控件被设置了 value 值,那么它们的值永远以被设置的值为准。值不变,value 就不会变化。

例如,上面设置了 <input />valuethis.state.usernameusernameconstructor 中被初始化为空字符串。即使用户在输入框里面尝试输入内容了,还是没有改变 this.state.username 是空字符串的事实。

所以应该怎么做才能把用户内容输入更新到输入框当中呢?在 React.js 当中必须要用 setState 才能更新组件的内容,所以我们需要做的就是:监听输入框的 onChange 事件,然后获取到用户输入的内容,再通过 setState 的方式更新 state 中的 username,这样 input 的内容才会更新。

...
    <div className='comment-field-input'>
      <input
        value={this.state.username}
        onChange={this.handleUsernameChange.bind(this)} />
    </div>
...

上面的代码给 input 加上了 onChange 事件监听,绑定到 this.handleUsernameChange 方法中,该方法实现如下:

...
  handleUsernameChange (event) {
    this.setState({
      username: event.target.value
    })
  }
...

在这个方法中,我们通过 event.target.value 获取 <input /> 中用户输入的内容,然后通过 setState 把它设置到 state.username 当中,这时候组件的内容就会更新,inputvalue 值就会得到更新并显示到输入框内。这时候输入已经没有问题了:

类似于 <input /><select /><textarea> 这些元素的 value 值被 React.js 所控制、渲染的组件,在 React.js 当中被称为受控组件(Controlled Component)。对于用户可输入的控件,一般都可以让它们成为受控组件,这是 React.js 所推崇的做法。另外还有非受控组件,这里暂时不提及。

同样地,让 <textarea /> 成为受控组件:

...
  handleContentChange (event) {
    this.setState({
      content: event.target.value
    })
  }
...
      <div className='comment-field'>
        <span className='comment-field-name'>评论内容:</span>
        <div className='comment-field-input'>
          <textarea
            value={this.state.content}
            onChange={this.handleContentChange.bind(this)} />
        </div>
      </div>
...

向父组件传递数据

当用户在 CommentInput 里面输入完内容以后,点击发布,内容其实是需要显示到 CommentList 组件当中的。但这两个组件明显是单独的、分离的组件。我们再回顾一下之前是怎么划分组件的:

可以看到,CommentApp 组件将 CommentInputCommentList 组合起来,它是它们俩的父组件,可以充当桥接两个子组件的桥梁。所以当用户点击发布按钮的时候,我们就将 CommentInput 的 state 当中最新的评论数据传递给父组件 CommentApp ,然后让父组件把这个数据传递给 CommentList 进行渲染。

CommentInput 如何向 CommentApp 传递的数据?父组件 CommentApp 只需要通过 props 给子组件 CommentInput 传入一个回调函数。当用户点击发布按钮的时候,CommentInput 调用 props 中的回调函数并且将 state 传入该函数即可。

先给发布按钮添加事件:

...
      <div className='comment-field-button'>
        <button
          onClick={this.handleSubmit.bind(this)}>
          发布
        </button>
      </div>
...

用户点击按钮的时候会调用 this.handleSumit 方法:

...
  handleSubmit () {
    if (this.props.onSubmit) {
      const { username,content } = this.state
      this.props.onSubmit({username,content})
    }
    this.setState({ content: '' })
  }
...

handleSumit 方法会判断 props 中是否传入了 onSubmit 属性。有的话就调用该函数,并且把用户输入的用户名和评论数据传入该函数。然后再通过 setState 清空用户输入的评论内容(但为了用户体验,保留输入的用户名)。

修改 CommentApp.js ,让它可以通过传入回调来获取到新增评论数据:

class CommentApp extends Component {
  handleSubmitComment (comment) {
    console.log(comment)
  }

  render() {
    return (
      <div className='wrapper'>
        <CommentInput
          onSubmit={this.handleSubmitComment.bind(this)} />
        <CommentList />
      </div>
    )
  }
}

CommentApp 中给 CommentInput 传入一个 onSubmit 属性,这个属性值是 CommentApp 自己的一个方法 handleSubmitComment。这样 CommentInput 就可以调用 this.props.onSubmit(…) 把数据传给 CommenApp

现在在 CommentInput 中输入完评论内容以后点击发布,就可以看到 CommentApp 在控制台打印的数据:

这样就顺利地把数据传递给了父组件,接下来我们开始处理评论列表相关的逻辑。

下一节中我们将介绍《React.js 小书 Lesson16 - 实战分析:评论功能(三)》

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom