react中componentWillReceiveProps()在props不改变的时候也可能被调用

前端之家收集整理的这篇文章主要介绍了react中componentWillReceiveProps()在props不改变的时候也可能被调用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

最近在写react时,需要在props被改变时更新一些东西,所以使用了componentWillReceiveProps方法,但是却发现该方法总是在各种没有改变props的情况下被调用,觉得很奇怪,遂询问我导师(我导师超厉害的!),我导师说这个方法确实有可能在props不改变的情况下被调用,所以需要在方法里手动判断一下this.props和nextProps是否相同,不相同了才执行我的更新方法。于是我抽空阅读了一下官方的文档https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/component_will_receive_props.html,研究了一下这个方法到底是怎么回事。下面先看一下componentDidMount()方法componentWillReceiveProps()方法的对比。

componentDidMount()在生命周期中只会被调用一次:

  • 在最开始的render后被调用(在所有的子元素都已经被render之后,并且所有的子元素都已经被调用它们的componentDidMounts 之后)
  • 组件在被卸载后的render(这确实是一个新的生命周期)

componentWillReceiveProps()在生命周期的第一次render后不会被调用,但是会在之后的每次render中被调用 = 当父组件再次传送props。

在react的update life cycle中,不得不提到componentWillReceiveProps方法。 该方法在props被传递给组件实例时被调用。下面详细地介绍了一下该方法

方法props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props获取,这里调用更新状态是安全的,并不会触发额外的render调用

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

传递props

方法最典型的用法是:当新的props被传递给组件时。例如,我们有一个Form组件和一个Person组件。Form组件有一个<input />,允许用户通过在其中输入来更改名称。 输入绑定到onChange事件并设置状态。状态值作为传递给Person组件。

Form.js

import React from 'react';
import Person './Person';

export default class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state        = { name: '' } ;
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({ name: event.currentTarget.value });
  }

  render() {
    return (
      <div>
        <input type="text" onChange={ this.handleChange } />
        <Person name={ this.state.name } />
      </div>
    );
  }
}

用户在输入框输入时,会使得在Person组件上调用componentWillReceiveProps(nextProps)方法传入新的prop值。我们可以通过调用this.props来获得旧的props,并且新值是传递给该方法nextProps参数。

更新 State

那么为什么我们需要componentWillReceiveProps? 因为在这里我们能抽取出新的props并且更新内部状态,比如我们可能有一些状态,这些状态是props的计算结果,那么我们就可以在这个方法里写逻辑,使用this.setState()来存储结果。

componentWillReceiveProps方法里使用this.setState(),能够在调用render()之前更新状态,来对prop转换做出反应。 旧的props可以通过this.props访问。 在这个函数调用this.setState()不会触发额外的渲染。

--https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops

Props may not change

注意:componentWillReceiveProps()方法调用,并不意味着props的值被改变。

为什么呢?数据可能在初始渲染和后续两次更新之间发生变化,而React无法知道数据有没有变化。 因此,React需要调用componentWillReceiveProps,因为组件需要被知会新的props(即使新props恰好与旧props相同)。

-- See(A => B) !=> (B => A)

假设我们有个prop,称为data,该prop是一个数组,如下所示:

// psuedo code
this.setState({ data: [1,2,31);">3] });

<MyComponent data={ this.state.data } /> 

如果在程序中对该data数组进行了push()操作,使得data数组的内容发生了变化,但是此时数组本身(引用)并没有改变,那么react便无法判断是否该数组内部内容发生了改变,因此为了避免很多问题,也为了避免要做花费很多的深层比较,react会调用componentWillReceiveProps()方法

因此componentWillReceiveProps()方法允许我们去检查、判断是否进来的新props发生了变更,让我们自己去做决定。我们只需要知道:当该方法调用时,并不意味着props肯定会不同。(Jim Sproch 的(A => B) !=> (B => A)讲得十分透彻,值得一读。)

你也许认为React应该使用更聪明的检查机制来判断props是否相等,但是这样会存在几个问题:

  • 当旧的props和新的props实际上是相同的物理对象时(只更改了对象的内部值),由于引用是triple-equals-equal,所以进行相等性的检查并不能告诉我们该值是否已更改,唯一可能的解决方案是创建数据的深层拷贝,然后再进行深入比较。但对于大型数据结构(特别是具有周期的数据结构)而言,所花费的代价可能过于昂贵。
  • props对象可能会包含 对函数的引用,这些函数可能会捕获闭包中的变量。 而React无法窥视这些闭包,因此React无法拷贝它们or验证相等性。
  • props对象可能包含对父对象渲染过程中重新实例化的对象的引用(即不是triple-equals-equal),但在概念上相等(即相同的键和相同的值)。深度比较(代价昂贵)可以检测到这一点,除了函数,因为没有可靠的方法来比较两个函数以判断它们是否在语义上等价。

Skipping this method

Mounting阶段的其他方法不同,并不是所有的更新阶段的方法都会每次被调用。 例如,如果update仅仅是因为一次状态更改而被触发,那么componentWillReceiveProps()将会被跳过。 回到我们上面的Form.js例子:

// ...
 handleChange(event) {
    return (
      <div>
        <input type="text" onChange={ this.handleChange } />
        <Person name={ this.state.name } />
      </div>
    );
  }
// ...

用户在输入框中输入时,将会触发一个setState()方法。这将在Form组件和Person组件中触发Update phase。对于Form组件来说,没有收到新的props,所以componentWillReceiveProps()将会被跳过。

猜你在找的React相关文章