59

为何要在componentDidMount里面发送请求?

 5 years ago
source link: https://jhanlu.github.io/2019/02/23/为何要在componentDidMount里面发送请求?/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在我们编写React代码的时候,总会遇到这么一个问题:请求接口并展示我们获取到的数据。这听起来很简单,但是你有没有想过一个问题:在何时进行进行网络请求才是最好的?我相信你们都会说,我当然知道,在 conpoenntDidMount 中啊,因为这是React官方推荐的,不服上个图

y6ziU3J.jpg!web

这一下你应该服了吧?服是服了,但为什么是 conpoentDidMountconstroutorcomponentWillMount 不可以吗?

首先我们来百度一下,这是一个最高赞的答案

qQ7r63q.jpg!web

总结一下:

  1. componentDidmount 是在组件完全挂载后才会执行,在此方法中调用 setState 会触发重新渲染,最重要的是,这是 官方 推荐的!

  2. constroutor 调用是在一开始,组件未挂载,所以不能用。

  3. componentWillMount 调用在 constroutor 后,在这里的代码调用 setState 不会出发重新渲染,所以不用。

  4. 还有一个没有出现在这里但听得最多的说法是:在 componentWillMount 里进行网络请求会阻碍组件的渲染。

  5. 反正就是要在 componetDidmount 里用!

说的好像挺有道理的,但是也感觉怪怪的,看的再多不如自己动手测试一下。首先测试一下 constroutor

constroutor

class Parentextends 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(因为跨域问题,请求无法成功,但是没有关系)

Vj2qQvQ.jpg!web

所以上面说的 constroutor 调用时组件未挂载,所以不能用的说法是错误的,组件未挂载也可以发送请求,这里所影响的时间只有执行发送请求的时间,然后组件接着渲染,等异步数据返回后,再执行 setState ,或许你会说,如果请求时间很短,在组件挂载之前就返回了怎么办,此时的 setState 还会起作用吗?别着急,这个问题后面会提到。

componentWillMount

将请求移到 componentWillMount

class Parentextends 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不会重新渲染吗?不是说网络请求会阻塞组件的渲染吗?然而都没有,其实原理跟constroutor是一样的,所影响的时间只有执行发送请求的时间,并不会阻塞组件的渲染,但不推荐使用 componentWillMount 是有其他的原因:

  1. 很重要的一点,React16.3后将会废弃掉componentWillMount、componentWillReceiveProps 以及 componentWillUpdate 三个周期函数,直到React 17前还可以使用,不过会有一个警告。

  2. 跟服务端渲染有关系(同构),如果在 componentWillMount 里获取数据,fetch data会执行两次,一次在服务端一次在客户端,使用 componentWillMount 则没有这个问题。

至于前面说到的数据在组件挂载前返回导致不生效的,这种情况并不会发生, 因为 setState 是将更新的状态放进了组件的__pendingStateQueue队列中,react并不会立即响应更新,会等到组件挂载完成后,再统一更新脏组件,见下图

ziaUJ3M.jpg!web

因此,从另外的角度看,放在constructor或者componentWillMount里面反而会更加有效率。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK