根据文档说法,从后台获取数据一定要放在componentDidMount里面调用,为什么不能在constructor或者componentWillMount里面调用?有什么不同?
根据文档说法,从后台获取数据一定要放在componentDidMount里面调用,为什么不能在constructor或者componentWillMount里面调用?有什么不同?
我一直想找到合理的答案,但是呢,这里说的感觉都不合理。
1.获取数据肯定是以异步方式进行,不会阻碍组件渲染(只会耽误请求发送这个时间),然后接着渲染,等异步返回数据后,如果成功再进行setState操作,setState是将更新的状态放进了组件的__pendingStateQueue队列,react不会立即响应更新,会等到组件挂载完成后,统一的更新脏组件(需要更新的组件)。放在constructor或者componentWillMount里面反而会更加有效率。
2.再说说React-Redux,要想让组件更新,必须要有用connect(...)(yourComponent)封装的容器(高阶)组件,这个组件会监听store变化,内部调用setState触发你的组件更新。数据处理都是通过dispatch(action)进行,自己并不会在组件的声明周期内直接ajax获取取数据。使用redux这个问题就成为了再组件声明周期的哪个节阶段dispatch(action)获取数据才合理?
总结:
我认为原因有:
1.跟服务器端渲染(同构)有关系,如果在componentWillMount里面获取数据,fetch data会执行两次,一次在服务器端一次在客户端。在componentDidMount中可以解决这个问题。
2.在componentWillMount中fetch data,数据一定在render后才能到达,如果你忘记了设置初始状态,用户体验不好。
3.react16.0以后,componentWillMount可能会被执行多次。
React16之后采用了Fiber架构,只有componentDidMount声明周期函数是确定被执行一次的,类似ComponentWillMount的生命周期钩子都有可能执行多次,所以不加以在这些生命周期中做有副作用的操作,比如请求数据之类。
1、通常我在componentWillMount发送ajax(渲染dom之前做的操作)
2、componentDidMount也可以做ajax操作(渲染dom完成之后做的操作)
那么,这2种情况如何区分呢?
需求1:
当你的render函数需要有数据才能渲染的时候,就在componentWillMount做操作。
render() {
return data && <div>{data}</div>
}
需求2:
当你的render不需要数据,先渲染dom结构,就在componentDidMount操作。
render() {
const { data } = this.props
return (
<div>
<span>我要先渲染</span>
<span>{data || ''}</span>
</div>
)
}
你既然了解的周期的顺序,那就很好理解了啊!willMount
在dom没有渲染前先进行的方法,如果这个时候请求ajax
那么势必会有等待的这一刻,然后排队渲染dom,而didMount
是在dom加载后在进行的方法,而这个时候请求ajax
前面没有任何等待,直接请求,然后如果你setState
那么整个虚拟dom
会在此渲染,此时再将获得的数据进行渲染,这样就感觉很顺的就执行下去了。而再次渲染的同时大部分的dom都是没有改变的,只有部分改变,所以渲染的速度会很快
感谢各位的回答:
总结一下不建议在constructor和componentWillMount里写的原因是
会阻碍组件的实例化,阻碍组件的渲染
如果用setState,在componentWillMount里面触发setState不会重新渲染
而在React Redux中,由于触发的渲染方式不同,是可以不需透过React组件的生命周期方法
,所以我感觉可以在生命周期的任何地方调用。当然,在consttructor和componentWillMount还是会阻碍一点点组件的实例化和渲染。
由于@eyesofkids写的全面一点,我采纳他的了。
constructor()中获取数据的话,如果时间太长,或者出错,组件就渲染不出来,你整个页面都没法渲染了。
componentDidMount()中能保证你的组件已经正确渲染。
把上面的答案综合整理下;写了这篇文章:react异步数据如ajax请求应该放在哪个生命周期?http://www.zhoulujun.cn/zhoul...
对于同步的状态改变,是可以放在componentWillMount,对于异步的,最好好放在componentDidMount。但如果此时有若干细节需要处理,比如你的组件需要渲染子组件,而且子组件取决于父组件的某个属性,那么在子组件的componentDidMount中进行处理会有问题:因为此时父组件中对应的属性可能还没有完整获取,因此就让其在子组件的componentDidUpdate中处理。
至于为什么,先看看react的生命周期:
constructor() 》componentWillMount() 》render() 》componentDidMount()
上面这些方法的调用是有次序的,由上而下,也就是当说如果你要获取外部数据并加载到组件上,只能在组件"已经"挂载到真实的网页上才能作这事情,其它情况你是加载不到组件的。
componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。此外,在这方法中调用setState方法,会触发重渲染。所以,官方设计这个方法就是用来加载外部数据用的,或处理其他的副作用代码。
constructor被调用是在组件准备要挂载的最一开始,所以此时组件尚未挂载到网页上。
componentWillMount方法的调用在constructor之后,在render之前,在这方法里的代码调用setState方法不会触发重渲染,所以它一般不会用来作加载数据之用,它也很少被使用到。
一般的从后台(服务器)获取的数据,都会与组件上要用的数据加载有关,所以都在componentDidMount方法里面作。虽然与组件上的数据无关的加载,也可以在constructor里作,但constructor是作组件state初绐化工作,并不是设计来作加载数据这工作的,所以所有有副作用的代码都会集中在componentDidMount方法里。
constructor()中获取数据的话,如果时间太长,或者出错,组件就渲染不出来,你整个页面都没法渲染了。
componentDidMount()中能保证你的组件已经正确渲染。
总结下:
1.跟服务器端渲染(同构)有关系,如果在componentWillMount里面获取数据,fetch data会执行两次,一次在服务器端一次在客户端。在componentDidMount中可以解决这个问题。
2.在componentWillMount中fetch data,数据一定在render后才能到达,如果你忘记了设置初始状态,用户体验不好。
3.react16.0以后,componentWillMount可能会被执行多次。
参考:
segmentfault: React数据获取为什么一定要在componentDidMount里面调用?
React 异步渲染组件优化
8 回答5.8k 阅读✓ 已解决
9 回答9.2k 阅读
6 回答4.7k 阅读✓ 已解决
5 回答3.5k 阅读✓ 已解决
4 回答7.9k 阅读✓ 已解决
7 回答9.8k 阅读
5 回答7.1k 阅读✓ 已解决
这与React组件的生命周期有关,组件挂载时有关的生命周期有以下几个:
constructor()
componentWillMount()
render()
componentDidMount()
上面这些方法的调用是有次序的,由上而下,也就是当说如果你要获取外部数据并加载到组件上,只能在组件"已经"挂载到真实的网页上才能作这事情,其它情况你是加载不到组件的。
componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。此外,在这方法中调用setState方法,会触发重渲染。所以,官方设计这个方法就是用来加载外部数据用的,或处理其他的副作用代码。
constructor被调用是在组件准备要挂载的最一开始,所以此时组件尚未挂载到网页上。
componentWillMount方法的调用在constructor之后,在render之前,在这方法里的代码调用setState方法不会触发重渲染,所以它一般不会用来作加载数据之用,它也很少被使用到。
一般的从后台(服务器)获取的数据,都会与组件上要用的数据加载有关,所以都在componentDidMount方法里面作。虽然与组件上的数据无关的加载,也可以在constructor里作,但constructor是作组件state初绐化工作,并不是设计来作加载数据这工作的,所以所有有副作用的代码都会集中在componentDidMount方法里。
补充一下,Redux作初始数据载入时,是可以不需透过React组件的生命周期方法,大致的方式如下代码:
为何可以这样作的原因,是Redux的store中的状态有一个最初始的值(reducer上传参里的默认值),组件先初始化完成,接著异步的fetch用promise语法,在作完外部数据加载后,发送动作出来,此时reducer更动store里的状态,react-redux绑定器会触发React组件的重渲染,所以组件上数据会自动更新。
有问题再问吧,代码写得简略但测试过是可执行的。