React(四) 事件总线,setState的原理,PureComponent优化React性能,ref获取类组件与函数组件

一、全局事件总线

安装第三方库npm install hy-event-store
发送数据的组件触发事件emit('事件名',参数)

// Son.jsx
  sendData () {
   
   
    // 触发事件,"tom", 100, 7.5是传递的参数
    eventBus.emit('getData', "tom", 100, 7.5)
  }
  render () {
   
   
    return (
      <div>
        <h2>Son组件</h2>
        <button onClick={
   
   this.sendData}>传递数据</button>
      </div>
    )
  }

接收数据的组件绑定事件
绑定:xxx.on('事件名',绑定的函数,[this指向的值]) (this指向的值是可选的)
解绑:xxx.off('事件名',绑定的函数)

// App.jsx
  componentDidMount () {
   
   
    // 绑定事件,当getData事件被触发时,调用函数showData
    eventBus.on('getData', this.showData)
  }
  componentWillUnmount () {
   
   
    // 解绑
    eventBus.off('getData', this.showData)
  }
  showData (name, nums, score) {
   
   
    console.log('showData', name, nums, score,);
    this.setState({
   
    name, nums, score }) // 此时this指向undefined
  }

这里同样需要注意this的指向问题。这里有三种方式确定this指向

 componentDidMount () {
   
   
    // 绑定事件
    // eventBus.on('getData', this.showData)
    // 方式一: on的第三个参数可指定this指向
    eventBus.on('getData', this.showData, this)
    // 方式二: 箭头函数
    eventBus.on('getData', (name, nums, score) => this.showData(name, nums, score))
  }
  
  // 方式三:es6的class fileds
  showData = (name, nums, score) => {
   
   
    this.setState({
   
    name, nums, score })
  }

二、setState的原理

1. 为什么要使用setState修改数据

Vue和React数据管理与渲染界面的区别:

  因为Vue做了数据劫持,当数据变化时,Vue能够监听到数据的变化,然后底层的set方法调用了render()函数重新渲染页面。所以Vue用起来感觉是会自动渲染,不用我们手动调用render()函数。

  而React没有数据劫持,如果通过this.state.msg = 'xxx'来修改数据,Reac并不知道该数据发生变化,也就不会刷新页面。
如何让React得知数据发生变化?就是调用setState()来修改数据,调用这个函数就相当于通知React数据发生了更新,需要重新渲染界面,React就会调用render()函数。

总结:
  React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化;我们必须通过setState来告知React数据已经发生了变化;

问:在组件中并没有实现setState的方法,为什么可以调用呢?
答:因为setState方法是从Component中继承过来的。

2. setState的三种用法

(1) 基本使用

setState({....})

  this.state = {
   
   
    msg: 'Hello World',
    counter: 0
  }
  ...
  // 点击按钮,调用changeText函数,修改msg
 changeText () {
   
   
   this.setState({
   
   
     msg: 'Hello Money'
   })
 }

setState里创建了一个新对象赋给state。从内存的角度来看是这样的:
在这里插入图片描述
新对象里没有counter,为什么新对象没有把旧对象覆盖掉呢?
底层其实是用了Object.assign(this.state,setState的新对象),把两个对象做了合并。然后在合适的时机再调用render()渲染。

(2) 传入回调函数

好处一: 可以在回调函数中编写对新state处理的逻辑
好处二: 当前的回调函数会将之前的state和props传递进来

changeText () {
   
   
 this.setState((state, props) => {
   
   
   console.log(state.msg, props) //打印 Hello World,空数组(因为props没值)
   return {
   
   
     msg: "你好啊, 李银河"
   }
 })
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值