React生命周期 - Go语言中文社区

React生命周期


更新于2019-8-27
react生命周期图示(旧):
react生命周期

1、propType和defaultProps

propType用于检测props数据的类型,类型不符时会报错,但对于不确定和无效的值它不会捕捉到错误,比如null。应用举例:

class Son extends React.Component {
render () {
  return (
    <div>我今年{this.props.age}岁啦!</div>
  )
}
}

Son.propTypes = {
age: PropTypes.number
}

class Father extends React.Component {
render () {
  return (
    <div>
    这是我的儿子:
    <Son age="3"/> //报错:prop `age` of type `string` supplied to `Son`, expected `number`
    <Son age={3}/> //正确
    </div>
  )
}
}
ReactDOM.render(<Father/>, document.getElementById('root'))

注意:当时用propTypes时需要引入依赖:import propTypes from ‘prop-types’
defaultProps用于设置默认的props,用于没有相应props传入时的备选,应用举例:

function App (props) {
return (
  <div>Hello {props.name}! {props.test}</div>
)
}

App.defaultProps = {
name: 'name',
test: 'I am test'
}

ReactDOM.render(<App name="Mary"/>, document.getElementById('root'))

运行结果为:Hello, Mary!I am test

2、构造函数

当没有用constructor显式定义时,就使用默认的构造函数。禁止在构造函数中调用setState。常在构造函数中干的事情:
1、在构造函数中定义this.state(此时也可以取到this.props)。
2、为自定义方法绑定this

3、componentWillMount() (旧,React 16 已弃用)

钩子函数,只在组件初始化时调用,在组件更新时不调用,整个生命周期中只调用这一次。

4、render()

组件渲染,该步骤包括构建虚拟dom,利用diff算法进行新旧虚拟dom的比较,以及更新实际的dom树。
react突出的特点就是拥有极速的渲染性能,这都要归功于虚拟dom和diff算法。虚拟dom实际上就是一个js对象,这个对象是用来描述实际的dom树的,但它省略了dom结点共同的属性和方法,只包含一些层级关系和关键的信息,比如标签名,属性,子节点等,这样对象就简洁了很多。并且相对于DOM对象,处理js对象会更快。
当数据变更的时候首先会更新虚拟dom,然后将新旧两个虚拟dom进行对比,因为在前段中很少会跨层移动元素,所以diff算法只对同层之间的元素进行比较。进行深度优先遍历,每个节点都有一个唯一的标记,如果有差异就记录到一个patch对象里面,比如替换了原来的结点,删除或替换了子结点,更改了文本内容等。还有一种差异类型是把一个结点的子节点重新排序了,这时候会进行列表的对比,知道新旧列表后求最小插入、删除距离,简化之后就是最小编辑距离问题,最常见的的解决算法是Levenshein Distance算法。注意,进行列表对比时每一个子节点都需要一个唯一的key来作为唯一标识。
最后我们通过打补丁的方式更新我们的dom树。
它的返回值有以下几种:

  • 原生DOM
  • React组件
  • Fragment (React 16新增)
  • 数字和字符串(会被渲染为Text节点)
  • Boolen和Null,不会被渲染出来
  • Portals (React 16新增)

render是渲染函数,所以只应该在里面定义与返回渲染内容,不应该作数据请求和业务逻辑的操作,这些应该放到componentDidMount或是componentDidUpdate中。

5、componentDidMount()

组件挂载之后调用,一个生命周期只调用一次。此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount中取消订阅。
在componentDidMount中调用setState会触发一次额外的渲染,多调用了一次render函数,但是用户对此没有感知,因为它是在浏览器刷新屏幕前执行的,但是我们应该在开发中避免它,因为它会带来一定的性能问题,我们应该在constructor中初始化我们的state对象,而不应该在componentDidMount调用setSstate方法

6、componentWillReceiveProps(nextProps) (旧,React 16 已弃用)

组件初始化时不调用,组件在接收新的props时调用。

7、shouldComponentUpdate(nextProps, nextState)

有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true
注意当我们调用forceUpdate并不会触发此方法
比如当调用了setState而新旧state没有发生任何差异的时候,就不需要进行render,我们就可以在这个钩子函数中对比新旧state的值,如果没有差异则返回false从而避免了重新渲染。(props同理)官方推荐使用PureComponent来代替该函数。

8、componentWillUpdate() (旧,React 16已弃用)

组件初始化时不调用,只在组件更新时调用。

9、componentDidUpdate()

组件更新完成后调用,此时可以获取dom结点。

10、componentWillUnmount()

组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

11、static getDerivedStateFromProps(nextProps, prevState)(React 16新增)

会在挂载、接收到新的props、调用了setState和forceUpdate时调用。接收两个参数,nextProps新的props参数,prevState当前state对象,返回一个对象,用于更新当前的state对象或者是null(表示当前state对象不需要更新)。由于它所替代的两个旧的生命周期函数都是在render之前触发,所以在它里面调用setState不会造成重新渲染。注意:它是个static方法,不是生命周期函数
示例:

class ExampleComponent extends React.Component {
  state = {
    isScrollingDown: false,
    lastRow: null
  }
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.currentRow !== prevState.lastRow) {
        return {
            isScrollingDown:
            nextProps.currentRow > prevState.lastRow,
            lastRow: nextProps.currentRow
        }
    }
    return null
  }
}

12、getSnapshotBeforeUpdate(prevProps, prevState) (React 16新增)

代替原来的componentWillUpdate,会在render和componentDidUpdate之间调用,必须有返回值,没有时也要返回null,否则会报错;必须和componentDidUpdate一起使用,否则也会报错。
示例:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // If we have a snapshot value, we've just added new items.
    // Adjust scroll so these new items don't push the old ones out of view.
    // (snapshot here is the value returned from getSnapshotBeforeUpdate)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

附上react 16组件生命周期图
在这里插入图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/little_little0_0/article/details/88667979
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢