React 的生命周期

React v16.0前的生命周期

其实大部分团队不见得会跟进升到16版本,所以16前的生命周期还是很有必要掌握的,何况16也是基于之前的修改

5caca39f0001b0a619201080.jpg

生命周期可分为四个阶段:

1. 组件初始化(initialization)阶段:

- constructor 方法
  1. 组件一创建就会调用 es6 class类中的 constructor 方法(最先执行)
  2. super(props)`用来调用类的构造方法( constructor() ), 也将父组件的props注入给子组件,子组件中props只读不可变,state可变
  3. constructor()用来做一些组件的初始化工作,如定义this.state的初始内容
class TodoList extends Component {
    // 组件一创建最先执行,早于render
    constructor(props) {
        super(props);
        this.state = {
            inputValue: '',
            list: []
        }
    }
}

2. 组件的挂载(Mounting)阶段(已插入真实 DOM)

- componentWillMount 方法

在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用

- render 方法

根据组件的props和state(两者的重传递和重赋值,无论值是否有变化,都可以引起组件重新render) ,当父组件的 render 函数被运行时, 它的子组件的 render 函数也会被重新运行

return 一个React元素(描述组件,即JSX模板),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。

- componentDidMount 方法

组件挂载到DOM后调用,且只会被调用一次

3. 组件的更新(Updating)阶段

- componentWillReceiveProps 方法(nextProps)

(只跟父组件传过来的 props 的变化有关,所以只有能接受 props 参数的子组件才有这个方法)

此方法只调用于props引起的组件更新过程中,参数nextProps是父组件传给当前组件的新props

而且这个组件第一次存在于父组件的是时候不会被执行(就是第一次不会执行,以后如果 nextProps 参数有变化才会被执行

class Child extends Component {
    constructor(props) {
        super(props);
        this.state = {
            someThings: props.someThings
        };
    }
    componentWillReceiveProps(nextProps) { // 父组件重传props时就会调用这个方法
        this.setState({someThings: nextProps.someThings});
    }
    render() {
        return <div>{this.state.someThings}</div>
    }
}
- shouldComponentUpdate(nextProps, nextState) 方法

此方法通过比较nextProps,nextState及当前组件的this.props,this.state,返回true时当前组件将继续执行更新过程,返回false则当前组件更新停止,以此可用来减少组件的不必要渲染,优化组件性能。

   shouldComponentUpdate(nextStates){ // 应该使用这个方法,否则无论state是否有变化都将会导致组件重新渲染
        if(nextStates.someThings === this.state.someThings){
          return false
        }
    }
- componentWillUpdate(nextProps, nextState) 方法

此方法在调用render方法前执行,在这边可执行一些组件更新发生前的工作,一般较少用

- render 方法

render方法在上文讲过,这边只是重新调用

- componentDidUpdate(prevProps, prevState)

此方法在组件更新后被调用,可以操作组件更新的DOM,prevProps和prevState这两个参数指的是组件更新前的props和state

4. 卸载阶段

- componentWillUnmount 方法

此方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清楚组件中使用的定时器,清楚componentDidMount中手动创建的DOM元素等,以避免引起内存泄漏。

完整的生命周期在 React 组件中的应用

class TodoList extends Component {

  constructor(props) {
    console.log('constructor');
    super(props);
    this.state = {
      list: [],
      inputValue: ''
    }
  }

  // 组件加载前
  componentWillMount() {
    console.log('componentWillMount');
  }

  // nextProps 参数变化后执行 第一次不执行
  componentWillReceiveProps(nextProps) { // 只有子组件有
    console.log('componentWillReceiveProps');
  }

  // shouldComponentUpdate 在组件更新前比较参数和数据,自己返回布尔值,优化组件性能 
  shouldComponentUpdate(nextStates){
    console.log('shouldComponentUpdate');
    return true;
    // if(nextStates.someThings === this.state.someThings){
    //   return false
    // }
}

  // componentWillUpdate 在 render 前执行
  componentWillUpdate() {
    console.log('componentWillUpdate');
  }

  // 生成描述文件 和 渲染
  render() {
    console.log('render');
    return (
      <Fragment>
        <div className="App">
          <div className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
          </div>
          <div>
          <input className='target' value={this.state.inputValue} onChange={this.handleInputChange} />
          <button className='red-btn' onClick={this.handleBtnClick}>add</button>
          </div>
          <ul>
            {
              this.getTodoItems()
            }
          </ul>
        </div>
      </Fragment>
    );
  }

  // 组件加载后
  componentDidMount() {
    console.log('componentDidMount');
  }

  // componentDidUpdate 在组件更新后被调用
  componentDidUpdate() {
    console.log('componentDidUpdate');
  }


  // componentWillUnmount 在组件被卸载前调用
  componentWillUnmount() {
    console.log('componentWillUnmount');
  }
}

React v16.4 的生命周期

1558239253(1).jpg

新引入了两个新的生命周期函数

- getDerivedStateFromProps 方法

在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容

- getSnapshotBeforeUpdate 方法

在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()

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

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 我们是否在 list 中添加新的 items ?
    // 捕获滚动​​位置以便我们稍后调整滚动位置。
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
    // 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
    //(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

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

在上述示例中,重点是从 getSnapshotBeforeUpdate 读取 scrollHeight 属性,因为 “render” 阶段生命周期(如 render)和 “commit” 阶段生命周期(如 getSnapshotBeforeUpdatecomponentDidUpdate)之间可能存在延迟。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容