React.js

理解React

2018-06-05  本文已影响68人  helloyoucan
React v16.4.0

一、理解优点

1、虚拟DOM
2、合成事件(SyntheticEvent)

1、虚拟DOM

在React中,render执行的结果得到的并不是真正的DOM节点,而仅仅是JavaScript对象,称之为虚拟DOM。

虚拟DOM是在DOM的基础上建立了一个抽象层,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。

虚拟DOM的原理:

React会在内存中维护一个虚拟DOM树,对这个树进行读或写,实际上是对虚拟DOM进行。当数据变化时,React会自动更新虚拟DOM,然后将新的虚拟DOM和旧的虚拟DOM进行对比,找到变更的部分,得出一个diff,然后将diff放到一个队列里,最终批量更新这些diff到DOM中。

虚拟DOM的优点:

最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染。

虚拟DOM的缺点:

首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。

2、合成事件(SyntheticEvent)

因为在浏览器中直接操作DOM会占用很大的内存,并且绑定浏览器事件也会占用一定的内存(绑定事件越多,占用内存越大)。所以,React实现了一套合成系统,简化了事件逻辑,同时解决了浏览器(FF浏览器和IE浏览器)的兼容问题

基本原理是

在JSX上面声明的所有事件,都会别委托在最外层的document节点上(事件委托),并且根据事件的名和组件名存储回调函数(listenerBank),当某个组件触发事件是,在在document节点上绑定的监听函数(dispatchEvent),就会找到这个组件和它的所有父组件(ancestors),对每个组件创建对应React合成事件(SyntheticEvent)并批处理(runEventQueueInBatch(events)),从而根据事件名和组件名调用(invokeGuardedCallback)回调函数。

但是

由于React合成事件系统模拟事件冒泡的方法是构建一个自己及父组件队列,因此也带来一个问题,合成事件不能阻止原生事件,原生事件可以阻止合成事件。用 event.stopPropagation() 并不能停止事件传播,应该使用 event.preventDefault()。

二、组件的生命周期

为了更好地理解React组件的生命周期,编写了如下代码

//Father.js
import React from 'react'
import Child from './Child.js'
export default class Father extends React.Component{
constructor(){
    super()
    this.state={
      randomData:0,
      hasChild:true
    }
    console.log('father constructor')
  }
  componentWillMount(){
    console.log('father componentWillMount')
  }
  componentDidMount(){
    console.log('father componentDidMount')
  }
  componentWillReceiveProps(nextProps){
    console.log('father componentReceiveProps')
  }
  shouldComponentUpdate(nextProps,nextState){
    console.log('father shouldComponentUpdate nextProps:'
      +JSON.stringify(nextProps)
      +'------nextState:'
      +JSON.stringify(nextState))
    return true
  }
  componentWillUpdate(){
    console.log('father componentWillUpdate')
  }
  componentDidUpdate(){
    console.log('father componentDidUpdate')
  }
  componentWillUnmount(){
    console.log('father componentWillUnmount')
  }
  handleChangeState(){
    this.setState({
      randomData:Math.floor(Math.random()*100)
    })
  }
  handleChangeChild(){
     this.setState({
      hasChild:!this.state.hasChild
    })
  }

  render(){
    console.log('father render')
    return (
      <div>
          <h1>Father State ---{this.state.randomData}</h1>
          <button onClick={this.handleChangeState.bind(this)}>Change</button>
          <p><button onClick={this.handleChangeChild.bind(this)}>{this.state.hasChild?'hide':'show'}</button></p>
          {this.state.hasChild?( <Child data={this.state.randomData} />):''}
      </div>
      )
  }
}
//Child.js
import React from 'react'
export default class Child extends React.Component{
    constructor(){
        super()
        console.log('child constructor')
    }
    componentWillMount(){
        console.log('child componentWillMount')
    }
    componentDidMount(){
        console.log('child componentDidMount')
    }
    componentWillReceiveProps(nextProps){
        console.log('child componentReceiveProps')
    }
    shouldComponentUpdate(nextProps,nextState){
        console.log('child shouldComponentUpdate nextProps:'
            +JSON.stringify(nextProps)
            +'------nextState:'
            +JSON.stringify(nextState))
         return true
    }
    componentWillUpdate(){
        console.log('child componentWillUpdate')
    }
    componentDidUpdate(){
        console.log('child componentDidUpdate')
    }
    componentWillUnmount(){
        console.log('child componentWillUnmount')
    }
    render(){
        console.log('child render')
        return (<h2>child recive props---{this.props.data}</h2>)
    }
}

运行结果如下


image.png

控制台输出的内容如下

father constructor
father componentWillMount
father render
child constructor
child componentWillMount
child render
child componentDidMount
father componentDidMount

点击Change按钮,
页面变化如下


image.png

控制台输入结果如下

father shouldComponentUpdate nextProps:{}------nextState:{"randomData":18,"hasChild":true}
father componentWillUpdate
father render
child componentReceiveProps
child shouldComponentUpdate nextProps:{"data":18}------nextState:null
child componentWillUpdate
child render
child componentDidUpdate
father componentDidUpdate

点击hide按钮,
页面变化如下


image.png

控制台输入结果如下

father shouldComponentUpdate nextProps:{}------nextState:{"randomData":18,"hasChild":false}
father componentWillUpdate
father render
child componentWillUnmount
father componentDidUpdate

点击show按钮,
页面变化如下


image.png

控制台输入结果如下

father shouldComponentUpdate nextProps:{}------nextState:{"randomData":18,"hasChild":true}
father componentWillUpdate
father render
child constructor
child componentWillMount
child render
child componentDidMount
father componentDidUpdate

由控制台输出的内容顺序可以理解到React组件各个生命周期钩子函数的执行顺序

下图可以更好地理解组件的生命周期


React生命周期.png
上一篇下一篇

猜你喜欢

热点阅读