You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate// 组件收到新的 props(props 中的数据并不一定真正发生变化)-> 决定是否需要继续执行更新过程 -> 组件代表的虚拟 DOM 即将更新 -> 组件重新计算出新的虚拟 DOM -> 虚拟 DOM 对应的真实 DOM 更新到真实 DOM 树中
组件在挂载完成后,因为 setState 的调用,将立即执行一次更新过程。虽然 render 方法被调用了两次,但这并不会导致浏览器界面更新两次,实际上,两次 DOM 的修改会合并成一次浏览器界面的更新。React 官网介绍 componentDidMount 方法时也有以下说明:
Calling setState() in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
这说明,组件 render 的次数 不一定等于 浏览器界面更新次数。虽然 JS 的执行和 DOM 的渲染分别由浏览器不同的线程完成,但 JS 的执行会阻塞 DOM 的渲染,而上面的两次 render 是在一个 JS 事件周期内执行的,所以在两次 render 结束前,浏览器不会更新界面。
React 深入系列4:组件的生命周期
组件是构建 React 应用的基本单位,组件需要具备数据获取、业务逻辑处理、以及 UI 呈现的能力,而这些能力是要依赖于组件不同的生命周期方法的。组件的生命周期分为 3 个阶段:挂载阶段、更新阶段、卸载阶段,每个阶段都包含相应的生命周期方法。因为是深入系列文章,本文不会仔细介绍每个生命周期方法的使用,而是会重点讲解在使用组件生命周期时,经常遇到的疑问和错误使用方式。
服务器数据请求
初学者在使用 React 时,常常不知道何时向服务器发送请求,获取组件所需数据。对于组件所需的初始数据,最合适的地方,是在
componentDidMount
方法中,进行数据请求,这个时候,组件完成挂载,其代表的 DOM 已经挂载到页面的 DOM 树上,即使获取到的数据需要直接操作 DOM 节点,这个时候也是绝对安全的。有些人还习惯在constructor
或者componentWillMount
中,进行数据请求,认为这样可以更快的获取到数据,但它们相比componentDidMount
的执行时间,提前的时间实在是太微乎其微了。另外,当进行服务器渲染时(SSR),componentWillMount
是会被调用两次的,一次在服务器端,一次在客户端,这时候就会导致额外的请求发生。组件进行数据请求的另一种场景:由父组件的更新导致组件的
props
发生变化,如果组件的数据请求依赖props
,组件就需要重新进行数据请求。例如,新闻详情组件 NewsDetail,在获取新闻详情数据时,需要传递新闻的id
作为参数给服务器端,当 NewsDetail 已经处于挂载状态时,如果点击其他新闻,NewsDetail 的 componentDidMount 并不会重新调用,因而 componentDidMount 中进行新闻详情数据请求的方法也不会再次执行。这时候,应该在componentWillReceiveProps
中,进行数据请求:如果进行数据请求的时机是由页面上的交互行为触发的,例如,点击查询按钮后,查询数据,这时只需要在查询按钮的事件监听函数中,执行数据请求即可,这种情况一般是不会有疑问的。
更新阶段方法的调用
组件的更新是组件生命周期中最复杂的阶段,也是涉及到最多生命周期方法的阶段。
正常情况下,当组件发生更新时,组件的生命周期方法的调用顺序如下:
父组件发生更新或组件自身调用 setState,都会导致组件进行更新操作。父组件发生更新导致的组件更新,生命周期方法的调用情况同上所述。如果是组件自身调用 setState,导致的组件更新,其生命周期方法的调用情况如下:
可见,这种情况下 componentWillReceiveProps 并不会被调用。
当组件的 shouldComponentUpdate 返回 false 时,组件会停止更新过程,这时候生命周期方法的调用顺序如下:
或(组件自身调用 setState,导致的组件更新):
setState 的时机
组件的生命周期方法众多,哪些方法中可以调用 setState 更新组件状态?哪些方法中不可以呢?
可以的方法
componentWillMount、componentDidMount、componentWillReceiveProps、componentDidUpdate
这里有几个注意点:
componentWillMount -> render -> componentDidMount
,组件并不会因为 componentWillMount 中的 setState 调用再次进行更新操作。如果是异步调用 setState,组件是会进行额外的更新操作。不过实际场景中很少在 componentWillMount 中调用 setState,一般可以通过直接在constructor
中定义 state 的方式代替。不可以的方法
其他生命周期方法都不能调用 setState,主要原因有两个:
render 次数 != 浏览器界面更新次数
先看下面的一个例子:
当我们观察浏览器渲染出的页面时,页面中 Test 所在 div 的背景色,是先显示红色,再变成黄色呢?还是直接就显示为黄色呢?
答案是:直接就显示为黄色!
这个过程中,组件的生命周期方法被调用的顺序如下:
组件在挂载完成后,因为 setState 的调用,将立即执行一次更新过程。虽然 render 方法被调用了两次,但这并不会导致浏览器界面更新两次,实际上,两次 DOM 的修改会合并成一次浏览器界面的更新。React 官网介绍 componentDidMount 方法时也有以下说明:
这说明,组件 render 的次数 不一定等于 浏览器界面更新次数。虽然 JS 的执行和 DOM 的渲染分别由浏览器不同的线程完成,但 JS 的执行会阻塞 DOM 的渲染,而上面的两次 render 是在一个 JS 事件周期内执行的,所以在两次 render 结束前,浏览器不会更新界面。
了解更多
➹:从 event loop 规范探究 javaScript 异步及浏览器更新渲染时机 · Issue #5 · aooy/blog
➹:浏览器的 16ms 渲染帧 - Harttle Land
The text was updated successfully, but these errors were encountered: