浅析React基本原理(笔记)

144 阅读3分钟

setState

更新数据

  • setState异步更新数据的
  • 注意: 使用该语法时,后面的setState()不要依赖于前面的setState()
  • 可以多次调用setState(),只会触发一次重新渲染
this.state = { count: 1 }
this.setState{{
    count: this.state.count + 1
}}
console.log(this.state.count)//1

推荐语法

  • 推荐:使用setState((state,props)=>{})语法
  • 参数state:表示最新的state
  • 参数props:表示最新的props
this.setState((state,props) => {
    return {
       count: state.count + 1
       }
  })
console.log(this.state.count)//1

这个语法也只会触发一次更新

第二个参数

  • 场景:在状态更新(页面完成重新渲染后)立即执行某个操作
  • 语法:setState(update[,callback])
this.setState(
    (state,props) => {},
    () => {console.log('这个回调函数会在状态更新后立即执行')}
 )
  • 使用推荐语法第二个参数,可以在回调函数里面依赖前面的setState()
state = {
   count: 1
  }
...
this.setState(
    (state,props) => {
       return {
      count: state.count + 1
          }
       },
       () => {
          console.log('状态更新完成',this.state.count)//状态更新完成: 2
       }
   )
   console.log(this.state.count)//1
...

JSX语法的转化过程

  • JSX仅仅是createElement()方法的语法糖(简化语法)
  • JSX语法被@babel/preset-react插件编译为createElement()方法
  • React元素: 是一个对象,用来描述你希望在屏幕上看到的内容
graph LR
JSX语法 --> createElement --> React元素

JSX语法

const element = (
   <h1 className="greeting">
      Hello JSX!
   </h1>
 );

createElement

const element = 
React.createElement(
    'hi',
    {className: 'greeting'},
    'Hello JSX!'
);

React元素

const element = {
   type: 'h1',
   props: {
      className: 'greeting',
      children: 'Hello JSX!'
   }
};

组件更新机制

  • setState()的两个作用:1.修改state 2.更新组件(UI)
  • 过程:父组件重新渲染时,也会重新渲染子组件,但只会渲染当前组件子树(当前组件及其所有子组件)

组件性能优化

减轻state

  • 减轻state:只储存跟组件渲染相关的数据(比如:count/列表数据/loading等)
  • 注意:不用做渲染的数据不要放在state中,比如定时器id等
  • 对于这种需要在多个方法中用到的数据,应该放在this中
class Hello extends Component {
  componentDidMount() {
    //timerId存储到this中,而不是state中
    this.timerId = setInterval(() => {}, 2000)
 }
 componentWillUnmount() {
    clearInterval(this.timerId)
   }
   render() { ... }
}

避免不必要的重新渲染

  • 组件更新机制:父组件更新会引起组件也被更新,这种思路很清晰
  • 问题:子组件没有任何变化时也会重新渲染
  • 如何避免不必要的重新渲染呢?
  • 解决方式:使用**钩子函数 shouldComponentUpdate(nextProps,nextState)
  • 作用:通过返回值决定该组件是否重新渲染,返回true表示重新渲染,false表示不重新渲染
  • 触发时机:更新阶段的钩子函数,组件重新渲染前执行(shouldComponentUpdate—>render)
class Hello extends Component {
   shouldComponentUpdate() {
     //根据条件,决定是否重新渲染组件
     return false
   }
   render() { ... }
}

纯组件

  • 说明:纯组件内部的对比是shallow compare(浅层对比)
  • 对于引用类型来说:只比较对象的引用(地址)是否相同
  • 注意:state或props中属性值为引用类型时,应该创建新数据,不要直接修改原数据!

虚拟DOM

执行过程

  1. 初次渲染时,React会根据初始state(Model),创建一个虚拟DOM对象(树)
  2. 根据虚拟DOM生成真正的DOM,渲染到页面。
  3. 当数据变化后(setState()),重新根据新的数据,创建新的虚拟DOM对象(树)。
  4. 与上一次得到的虚拟DOM对象,使用Diff算法对比(找不同),得到需要更新的内容。
  5. 最终,React只将变化的内容更新(patch)到DOM中,重新渲染到页面。