React JS在特定道具更改时调用组件方法的正确模式是什么?

时间:2018-04-11 10:29:53

标签: javascript reactjs react-native redux lifecycle

使用React和Redux,假设您有一个将请求发送到外部API的组件方法。

import React, { Component } from 'react';
import { connect } from 'react-redux';

class MyComp extends Component {

  boolUpdate (val) {
    fetch('http://myapi.com/bool', { val });
  }

  shouldComponentUpdate (nextProps) {
    return false;
  }

  render () {
    return <h1>Hello</h1>;
  }

}

const mapStateToProps = ({ bool }) => ({ bool });

export default connect(mapStateToProps)(MyComp);

现在让我们说每次boolUpdate()道具更改时都要调用bool,但这不应该触发组件更新,因为组件的渲染中没有任何内容受到影响。

在React中执行此操作的最佳方式是什么?

直到最近,人们常常做类似的事情:

componentWillReceiveProps (nextProps) {
  if (nextProps.bool !== this.props.bool) this.boolUpdate(nextProps.bool);
}

但是从React v16.3开始,componentWillReceiveProps()已被弃用。在此示例中,我们也无法使用componentDidUpdate(),因为shouldComponentUpdate()可以防止这种情况发生。 getDerivedStateFromProps()是一种静态方法,因此它无法访问实例方法。

因此,我们留下的唯一选择似乎是使用shouldComponentUpdate()本身。有点像:

shouldComponentUpdate (nextProps) {
  if (nextProps.bool !== this.props.bool) this.boolUpdate(nextProps.bool);
  return false;
}

这看起来相当&#34; hacky&#34;但对我而言,并不是shouldComponentUpdate()的目的。

是否有人有更好的建议模式?

是否有一种倾听特定道具变化和触发组件方法的首选方法?

谢谢!

2 个答案:

答案 0 :(得分:5)

如果您想在道具更改时运行一些代码(例如数据提取),请在componentDidUpdate中执行此操作。

componentDidUpdate(prevProps) {
  if (prevProps.id !== this.props.id) {
    this.fetchData();
  }
}

在您的示例中,这不起作用,因为shouldComponentUpdate返回false。我认为这不是一个非常常见的情况,因为如果道具发生变化,通常你仍然想要重新渲染。

例如,如果用户ID发生更改,您可能希望在加载新用户的数据时显示加载指示符。因此,在这种情况下避免重新渲染不是很有用

但是,如果您完全确定 需要阻止重新渲染需要执行副作用,例如在道具更改中获取数据,则可以将您的组件拆分为两个。外部组件将在componentDidUpdate中执行数据提取,并返回<InnerComponent {...this.props} />。内部组件将具有shouldComponentUpdate实现,以防止进一步重新呈现。同样,我不希望这是一个常见的情况,但你可以这样做。

答案 1 :(得分:4)

根据有关github的React docsthis讨论,基于道具更改获取新数据的位置实际上是componentDidUpdate

渲染实际上被分为两个阶段,Render Phase是纯粹的,没有副作用,Commit Phase可以运行副作用,可以使用DOM并安排更新。

你可以在Dan Abramov的图中看到这个解释: enter image description here

丹还提到:

  

人们习惯将这两种不同的东西混合在一起   componentWillReceiveProps,这就是为什么我们必须将它拆分成一个   纯方法(getDerivedStateFromProps)和现有的不纯方法   哪里可以做副作用(componentDidUpdate)。

对于解决方案本身,我附加了文档中的示例:

  

道具更改时获取外部数据

     

以下是基于道具值获取外部数据的组件示例:

     

在:

componentDidMount() {
  this._loadAsyncData(this.props.id);
}

componentWillReceiveProps(nextProps) {
  if (nextProps.id !== this.props.id) {
    this.setState({externalData: null});
    this._loadAsyncData(nextProps.id);
  }
}
     

后:

  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.id !== prevState.prevId) {
      return {
        externalData: null,
        prevId: nextProps.id,
      };
    }
    return null;
  }

  componentDidMount() {
    this._loadAsyncData(this.props.id);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }