likes
comments
collection
share

浅谈 React 组件的更新机制

作者站长头像
站长
· 阅读数 18

前言

我们知道 React 组件是通过 setState() 方法来更新数据的。所以在一个组件中,当我们调用 setState() 方法就会更新 state,并且会把更新后的 state 重新渲染到页面中,这不难理解,但是如果存在多个相关联的组件时,如果其中一个组件的 setState() 方法被调用,会发生什么?

分析

例如有以下代码:

// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// App组件
class App extends React.Component {
  state = {
    num: 0,
  }

  handleClick = () => {
    this.setState(state => ({ num: state.num + 1 }))
  }

  render() {
    console.log('App组件被调用')
    return (
      <div className='app' style={{ backgroundColor: '#00c9ff', padding: '20px' }}>
        <h1>App组件的num:{this.state.num}</h1>
        <button onClick={this.handleClick} style={{ marginBottom: '10px' }}>点我+1</button>
        <div className='app-wrapper' style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
          <Son1 />
          <Son2 />
        </div>
      </div>
    )
  }
}

class Son1 extends React.Component {
  state = {
    num: 0
  }

  handleClick = () => {
    this.setState(state => ({ num: state.num + 1 }))
  }

  render() {
    console.log('组件1被调用')
    return (
      <div className='parent1' style={{ backgroundColor: '#2196f3', width: '50%', padding: '20px', marginRight: '20px' }}>
        <h2>组件1的num:{this.state.num}</h2>
        <button onClick={this.handleClick} style={{ marginBottom: '10px' }}>点我+1</button>
        <div className='parent1-wrapper' style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
          <Child11 />
          <Child12 />
        </div>
      </div>
    )
  }
}

class Child11 extends React.Component {
  render() {
    console.log('组件1-1被调用')
    return (
      <div className='child11' style={{ backgroundColor: '#ffeb3b', height: '300px', width: '50%', marginRight: '20px' }}>
        组件1-1
      </div>
    )
  }
}

class Child12 extends React.Component {
  render() {
    console.log('组件1-2被调用')
    return (
      <div className='child12' style={{ backgroundColor: '#ffeb3b', height: '300px', width: '50%' }}>
        组件1-2
      </div>
    )
  }
}

class Son2 extends React.Component {
  state = {
    num: 0
  }

  handleClick = () => {
    this.setState(state => ({ num: state.num + 1 }))
  }

  render() {
    console.log('组件2被调用')
    return (
      <div className='parent2' style={{ backgroundColor: '#2196f3', width: '50%', padding: '20px' }}>
        <h2>组件2的count:{this.state.num}</h2>
        <button onClick={this.handleClick} style={{ marginBottom: '10px' }}>点我+1</button>
        <div className='parent2-wrapper' style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
          <Child21 />
          <Child22 />
        </div>
      </div>
    )
  }
}

class Child21 extends React.Component {
  render() {
    console.log('组件2-1被调用')
    return (
      <div className='child21' style={{ backgroundColor: '#ffeb3b', height: '300px', width: '50%', marginRight: '20px' }}>
        组件2-1
      </div>
    )
  }
}

class Child22 extends React.Component {
  render() {
    console.log('组件2-2被调用')
    return (
      <div className='child22' style={{ backgroundColor: '#ffeb3b', height: '300px', width: '50%' }}>
        组件2-2
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))

其页面渲染效果如下:

浅谈 React 组件的更新机制

其关系图如下:

浅谈 React 组件的更新机制

当我点击“组件1”中的按钮时控制台打印如下:

浅谈 React 组件的更新机制

通过分析可以得出以下结论:

  • 如果组件1中的 setState() 方法被调用,组件1本身及其子组件1-1和子组件1-2将重新渲染了
  • 父组件App,兄弟组件2,兄弟组件2的子组件2-1及子组件2-2并没有重新渲染

这说明当某个组件重新渲染时,其下面的组件树也会重新渲染,而该组件的父组件及兄弟组件树并不会受到影响。我们可以通过下面的操作来证明该说法。

点击“组件2”中的按钮结果如下图所示:

浅谈 React 组件的更新机制

点击App组件中的按钮结果如下图所示:

浅谈 React 组件的更新机制

以上整个过程展现的就是 React 组件的更新机制。