在咱们编写React代码的时候,总会遇到这么一个问题:请求接口并展现咱们获取到的数据。这听起来很简单,可是你有没有想过一个问题:在什么时候进行进行网络请求才是最好的?我相信大家都会说,我固然知道,在 componentDidMount
中啊,由于这是React官方推荐的,不服上个图javascript
这一下你应该服了吧?服是服了,但为何是 componentDidMount
? constructor
或 componentWillMount
不能够吗?java
首先咱们来百度一下,这是一个最高赞的答案react
总结一下:segmentfault
componentDidmount
是在组件彻底挂载后才会执行,在此方法中调用setState
会触发从新渲染,最重要的是,这是官方推荐的!跨域
constructor
调用是在一开始,组件未挂载,因此不能用。网络
componentWillMount
调用在 constructor
后,在这里的代码调用 setState
不会出发从新渲染,因此不用。异步
还有一个没有出如今这里但听得最多的说法是:在 componentWillMount
里进行网络请求会阻碍组件的渲染。函数
反正就是要在 componentDidmount
里用!测试
说的好像挺有道理的,可是也感受怪怪的,看的再多不如本身动手测试一下。首先测试一下 constructor
。fetch
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'plain text'
};
fetch('https://s.codepen.io')
.then(res => this.setState({text: 'success'}))
.catch(err => this.setState({text: 'error'}))
}
render() {
return (
<div> <h1>{this.state.text}</h1> </div>
);
}
}
ReactDOM.render(
<Parent/>,
document.getElementById('root')
);
复制代码
戳这里看演示,state从一开始的plain text变成了error(由于跨域问题,请求没法成功,可是没有关系)
因此上面说的constructor
调用时组件未挂载,因此不能用的说法是错误的,组件未挂载也能够发送请求,这里所影响的时间只有执行发送请求的时间,而后组件接着渲染,等异步数据返回后,再执行 setState
,或许你会说,若是请求时间很短,在组件挂载以前就返回了怎么办,此时的 setState
还会起做用吗?别着急,这个问题后面会提到。
将请求移到 componentWillMount
中
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'plain text'
};
}
componentWillMount() {
fetch('https://s.codepen.io')
.then(res => this.setState({text: 'success'}))
.catch(err => this.setState({text: 'error'}))
}
render() {
return (
<div> <h1>{this.state.text}</h1> </div>
);
}
}
ReactDOM.render(
<Parent/>,
document.getElementById('root')
);
复制代码
戳这里,能够看到,state也是从plain text 变成了error,嫌太快看不清楚的能够用setTimeout模拟一下。这就很奇怪了,不是说willMount里面setState不会从新渲染吗?不是说网络请求会阻塞组件的渲染吗?然而都没有,其实原理跟constructor是同样的,所影响的时间只有执行发送请求的时间,并不会阻塞组件的渲染,但不推荐使用 componentWillMount
是有其余的缘由:
很重要的一点,React16.3后将会废弃掉componentWillMount、componentWillReceiveProps 以及 componentWillUpdate 三个周期函数,直到React 17前还可使用,不过会有一个警告。
跟服务端渲染有关系(同构),若是在 componentWillMount
里获取数据,fetch data会执行两次,一次在服务端一次在客户端,使用 componentDidMount
则没有这个问题。
至于前面说到的数据在组件挂载前返回致使不生效的,这种状况并不会发生, 由于 setState
是将更新的状态放进了组件的__pendingStateQueue队列中,react并不会当即响应更新,会等到组件挂载完成后,再统一更新脏组件,见下图
所以,从另外的角度看,放在constructor或者componentWillMount里面反而会更加有效率。
感谢@名扬的提醒,React16引入了React Fiber
的概念,致使了componentWillMount
,componentWillReceiveProps
,shouldComponentUpdate
,componentWillUpdate
这些生命周期出现了可能被调用不止一次的可能,详情参见React Fiber是什么?,这应该也是上文提到的这些生命周期将会被废弃的缘由。
数据获取能够放在 constructor
或者 componentDidmount
中,不建议放在 componentWillMount
。 可是为了更好的代码规范和可读性,建议统一放在 componentDidmount
。
对于首次render没有数据,可能致使出错的。能够设置一个initial state,或者增长一个loading状态,加载数据时展现一个spinner或者骨架图都是比较经常使用的方案。