使用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()
的目的。
是否有人有更好的建议模式?
是否有一种倾听特定道具变化和触发组件方法的首选方法?
谢谢!
答案 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 docs和this讨论,基于道具更改获取新数据的位置实际上是componentDidUpdate
。
渲染实际上被分为两个阶段,Render Phase
是纯粹的,没有副作用,Commit Phase
可以运行副作用,可以使用DOM并安排更新。
人们习惯将这两种不同的东西混合在一起 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); } }