单页面应用的优缺点?
优点:
1、良好的交互体验好、快,内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
2、基于上面一点,减轻服务器压力小。
3、良好的前后端分离。SPA和RESTful架构一起使用,后端不再负责模板渲染、输出页面工作,web前端和各种移动终端地位对等,后端API通用化。
5、对前端人员javascript技能要求更高,促使团队技能提升。
缺点:
A:初次加载耗时相对增多,首屏加载慢。
1.如果不对路由进行处理,在加载首页的时候,就会将所有组件全部加载,并向服务器请求数据,这必将拖慢加载速度;
2.通过查看Network,发现整个网站加载试讲长达10几秒,加载时间最长的就是js、css文件和媒体文件及图片
解决方案:
1.router懒加载,懒加载就是按需加载组件,只有当路由被访问时才会加载对应的组件
2.在做项目时,我们会用到很多库,采用cdn加载可以加快加载速度。
3.异步加载组件
B:导航不可用,如果一定要导航需要自行实现前进、后退。
C:对开发人员技能水平、开发成本高。
vue和react的区别?
**1.**监听数据变化的实现原理不同
1.Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能
2.React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染
为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而React更强调数据的不可变。所以应该说没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。
因为一般都会用一个数据层的框架比如 Vuex 和 Redux,所以这部分不作过多解释,在最后的 vuex 和 redux的区别 中也会讲到。
**2.**数据流不同
大家都知道Vue中默认是支持双向绑定的。在Vue1.0中我们可以实现两种双向绑定:
父子组件之间,props 可以双向绑定
组件与DOM之间可以通过 v-model 双向绑定
在 Vue2.x 中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且 Vue2.x 已经不鼓励组件对自己的 props 进行任何修改了。
所以现在我们只有 组件 <--> DOM 之间的双向绑定这一种。
然而 React 从诞生之初就不支持双向绑定,React一直提倡的是单向数据流,他称之为 onChange/setState()模式。
不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。
3.Hoc****和mixins
在 Vue 中我们组合不同功能的方式是通过 mixin,而在React中我们通过 HoC (高阶组件)。
React 最早也是使用 mixins 的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了 mixinx 转而使用 HoC
而 Vue 一直是使用 mixin 来实现的。
**4.**组件通讯的区别
在Vue 中有几种方式可以实现组件通信:
1. 父组件通过props给子组件传值 或者 父组件通过$ref给子组件传值
2. 子组件通过$parent给父组件传值
3. 兄弟之间传值通过eventBus
4. 通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,可以跨越多个层级
在 React 中,也有对应的几种方式:
1. 父组件通过 props 可以向子组件传递数据或者回调
2. 兄弟:利用 redux 实现。
3. 所有关系都通用的方法:利用PubSub.js订阅
React 本身并不支持自定义事件,Vue中子组件向父组件传递消息有两种方式:事件和回调函数,而且Vue更倾向于使用事件。但是在 React 中我们都是使用回调函数的,这可能是他们二者最大的区别。
**
5.**模板渲染方式的不同
语法不同:
1. React 是通过JSX渲染模板
2. 而Vue是通过一种拓展的HTML语法进行渲染
原理不同:
1. React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的
2. Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现
对这一点,我个人比较喜欢React的做法,因为他更加纯粹更加原生,而Vue的做法显得有些独特,会把HTML弄得很乱。举个例子,说明React的好处:
react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。
**
6.vuex****和redux的区别**
从表面上来说,store 注入和使用方式有一些区别;
在 Vuex 中,$store 被直接注入到了组件实例中,因此可以比较灵活的使用:
1. 使用 dispatch 和 commit 提交更新
2. 通过 mapState 或者直接通过 this.$store 来读取数据
在 Redux 中,我们每一个组件都需要显示的用 connect 把需要的 props 和 dispatch 连接起来。
另外 Vuex 更加灵活一些,组件中既可以 dispatch action 也可以 commit updates,而 Redux 中只能进行 dispatch,并不能直接调用 reducer 进行修改。
从实现原理上来说,最大的区别是两点:
1、Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改
2、Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的(如果看Vuex源码会知道,其实他内部直接创建一个Vue实例用来跟踪数据变化)
而这两点的区别,其实也是因为 React 和 Vue的设计理念上的区别。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用 Vue 的感觉。
什么是虚拟 DOM?
虚拟dom也叫vdom;(virtual dom)
用js模拟DOM结构;
在react中,react会先将代码转换成一个js对象,然后将这个js对象转换成真正的DOM,这个js对象就是所谓的虚拟dom;
为什么虚拟 dom 会提高性能?
虚拟dom 相当于在 JS 和真实 dom 中间加了一个缓存,利用 diff 算法避免了没有必要的 dom 操作,从而提高性能。
1、用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了,然后在对其子节点进行比较,一层一层往下,直到没有子节点
在生命周期中的哪一步你应该发起 AJAX 请求?
我们应当将AJAX 请求放到 componentDidMount 函数中执行,主要原因有下:
1、React 下一代调和算法 Fiber 会通过开始或停止渲染的方式优化应用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会多次频繁调用 componentWillMount。如果我们将 AJAX 请求放到 componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。
2、如果我们将 AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 请求则能有效避免这个问题。
createElement 与 cloneElement 的区别是什么?
createElement 函数是 JSX 编译之后使用的创建 React Element 的函数,而 cloneElement 则是用于复制某个元素并传入新的 Props。
什么是 JSX,为什么以大写开头?
JSX 是 JavaScript 语法的扩展,它允许编写类似于 HTML 的代码
实际上, babel 帮我们将这个语法转换成,自定义组件必须大写的原因. babel 在编译的过程中会判断 JSX 组件的首字母, 如果是小写, 则为原生 DOM 标签, 就编译成字符串. 如果是大写, 则认为是自定义组件. 编译成对象.
类组件和函数组件有何不同?
在 React 16.8版本(引入钩子)之前,使用基于类的组件来创建需要维护内部状态或利用生命周期方法的组件
函数组件是无状态的(同样,小于 React 16.8版本),并返回要呈现的输出
HTML 和 React 事件处理有什么区别?
1、在 HTML 中事件名必须小写:
2、而在 React 中需要遵循驼峰写法:
3、在 HTML 中可以返回 false 以阻止默认的行为:
4、而在 React 中必须地明确地调用 preventDefault():
react-router的原理?
BrowserRouter 或 HashRouter 用来渲染Router所代表的组件
BrowserRouter (属于后端路由)很简洁没有#,但是需要 server 端配置
HasRouter (属于前端路由)会有一个#,通过这个# HTML 5 History进行前端跳转他的感觉像锚点
Route 用来匹配组件路径并且筛选需要渲染的组件
Switch 用来筛选需要渲染的唯一组件
为什么 React 元素有一个 $$typeof 属性?
目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。
React 中 keys 的作用是什么?
Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。
react组件之间如何通信?
父传子:props;
子传父:子调用父组件中的函数并传参;
兄弟:利用 redux 实现。
跨层级通信:
1.使用react 自带的 Context 进行通信,createContext 创建上下文, useContext 使用上下文
2.利用PubSub.js订阅
3.使用Redux 或者 Mobx 等状态管理库
状态(state)和属性(props)有何不同?
props 是从父组件传递到组件的数据。它们不应该被改变,而应该只显示或用于计算其他值。状态是组件的内部数据,可以在组件的生存期内修改,并在重新呈现之间进行维护。
调用 setState 之后发生了什么?
在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染,最后在commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素
传入 setState 函数的第二个参数的作用是什么?
该函数会在setState函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成。
this.setState({
username: 'tylermcginnis33'
}, () => console.log('setState')
)
为什么调用 setState 而不是直接改变 state?
如果您尝试直接改变组件的状态,React 将无法得知它需要重新渲染组件。通过使用setState()方法,React 可以更新组件的UI。
React 中的 setState 是同步还是异步?
在React16.8之前,React通过this.state来访问state,通过this.setState()方法来更新state。当this.setState()被调用的时候,React会重新调用render方法来重新渲染UI
1.合成事件中是异步
2.钩子函数中的是异步
3.原生事件中是同步
4.setTimeout中是同步
详细版本:
1、setState只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
2、setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
3、setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。
展示组件 (也叫 UI 组件)和容器组件(负责应用逻辑处理)之间有何不同?
展示组件(UI 组件)
负责展示 UI,也就是组件如何渲染,具有很强的内聚性
只关心得到数据后如何渲染
容器组件(逻辑组件)
负责应用逻辑处理,发送网络请求,处理返回数据,将处理过的数据传递给展示组件
也提供修改数据源的方法,通过展示组件的props传递给展示组件
当展示组件的状态变更引起源数据变化时,展示组件通过调用容器组件提供的方法同步这些变化
React受控组件和非受控组件?
1. React的受控组件与非受控组件的概念是相对于表单而言的
2. 在React中,表单元素通常会持有一下内部的state,因此,它的工作方式与其他HTML元素不一样,而获取表单元素内部state的实现方式的不同,就产生了受控组件和非受控组件
受控组件
前面提到,HTML的表单元素(如input、textarea、select等)在react中会维护内部的state;而react本身的数据也是由一个state来维护的,将这两者结合起来,react的state将表示该组件的值的变量的值传入表单内部,作为默认值,待表单内部有修改时,会通过setState同步到外界的state中。
例如:
input表单的值由this.state.value传入,onchange绑定的方法经过setState修改,组件的数据流动都是通过State控制的,就是一个受控组件
非受控组件
如果上例中的标的元素并不经过state,而是通过ref修改(或者直接操作DOM),那么它的数据无法通过state控制,这就是非受控组件
简单版本
表单数据状态受React的state控制,通过setState修改的就是受控组件,通过DOM控制,不受state控制的就是非受控组件
什么情况下需要使用 shouldComponentUpdate
在React中,默认情况下,如果父组件数据发生了更新,那么所有子组件都会无条件更新 !!!!!!
通过shouldComponentUpdate()retrun fasle 来判断阻止 Header 组件做无意义的更新
shouldComponentUpdate()并不是每次都需要使用,而是需要的时候才会优化
Redux 是什么?
redux 是一个应用数据流框架(状态容器);
Redux作用:解决了在开发过程中数据无限层层传递而引发的一系列问题。或者说是组件间状态共享的问题;
Redux缺点:概念偏多,理解起来不容易,样板代码太多;
Redux****三大原则:
单一数据源:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
State 是只读的:唯一改变 state 的方法就是触发action,action 是一个用于描述已发生事件的普通对象。
使用纯函数来执行修改:为了描述 action 如何改变 state tree ,你需要编写 reducers。
工作流程:
是 view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,
view 通过 store 提供的 getState 获取最新的数据新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,
减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,
但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们
Redux中间件原理
什么是Redux的中间件?Redux中间件其实是通过重写createStore来增强和扩展原来的dispatch方法,使其能够在执行dispatch的同时可以同步执行其它方法,比如redux-thunk就是一个处理异步的中间件;
中间件的使用方式是用applyMiddleWare把中间件作为参数传入createStore中,那么applyMiddleWare是如何实现的?在这之前我们先看下createStore方法的第三个参数是什么,我们回看下createStore源码:
export default function createStore(reducer, preloadedState, enhancer) {
...
// 增强器
// 第三个参数是enhancer,也就是我们传入的applyMiddleWare
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 在这里return了enhancer结果
// 传入了createStore,reducer,preloadedState
// 实际上是重写了createStore
return enhancer(createStore)(reducer, preloadedState)
}
...
}
用过哪些中间件?
redux-thunk:处理异步操作
redux-saga:处理异步操作
redux-promise:处理异步操作,actionCreator 的返回值是promise
react-redux 的实现原理?
通过 redux 和 react context 配合使用,并借助高阶函数,实现了 react-redux。
生命周期方法是什么?
基于类的组件可以声明在其生命周期中某些特定时刻调用的特殊方法,例如何时将其装入(渲染到 DOM 中)以及何时将其卸载
可以在组件中实现以下生命周期方法:
1. componentWillMount:在创建组件之后但在将其渲染到DOM中之前调用
2. componentDidMount:在第一个渲染之后调用;组件的DOM元素现在可用
3. componentWillUpdate:在收到新的props并且ComponentUpdate返回true时调用
4. componentDidUpdate:在组件更新后调用
5. componentWillUnmount:在组件从DOM中移除之前调用,允许您清理事件侦听器之类的内容。
6. componentWillReceiveProps:当属性更新时调用
7. shouldComponentUpdate:当收到新props时,此方法可以防止重新渲染以优化性能
必须记住的生命周期函数:
*******加载的时候:**componentWillMount、 render 、componentDidMount(dom操作)
*******更新的时候:**componentWillUpdate、render、componentDidUpdate
*****销毁的时候: componentWillUnmount
*******你在父组件里面改变props传值的时候触发的:**componentWillReceiveProps
React 的事件机制
1.为什么要手动绑定this
回调函数是直接调用调用的,并没有指定调用的组件,所以不进行手动绑定的情况下直接获取到的this是undefined。
2.****React事件和原生事件有什么区别
React 事件使用驼峰命名,而不是全部小写。
通过 JSX , 你传递一个函数作为事件处理程序,而不是一个字符串。
另一个区别是,在 React 中你不能通过返回 false 来阻止默认行为。必须明确调用preventDefault
React事件和原生事件的执行顺序?可以混用吗?
1. react的所有事件都挂载在document中
2. 当真实dom触发后冒泡到document后才会对react事件进行处理
3. 所以原生的事件会先执行
4. 然后执行react合成事件
5. 最后执行真正在document上挂载的事件
react事件和原生事件最好不要混用
原生事件中如果执行了stopPropagation方法,则会导致其他react事件失效。因为所有元素的事件将无法冒泡到document上。
什么是合成事件?React事件如何解决跨浏览器兼容?
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
这里, e 是一个合成的事件。 React 根据 W3C 规范 定义了这个合成事件,所以你不需要担心跨浏览器的兼容性问题。
不管在什么浏览器环境下,浏览器会将该事件类型统一创建为合成事件,从而达到了浏览器兼容的目的。
何为高阶组件(HOC)?
高阶组件 其实就是一个函数而已,只不过参数是一个组件而已,返回了一个新的组件
复用组件的业务逻辑 react-redux connect 其实就是一个高阶组件
React 中各种组件复用的优劣势(mixin、render props、hoc、hook)
mixin**:**
它的出现主要就是为了解决代码复用问题。
Mixin将通用共享的方法包装成Mixins方法,然后注入各个组件实现,事实上已经是不被官方推荐使用了
Mixin****的问题:
1、Mixin引入了隐式依赖关系
2、Mixin导致名称冲突
3、随着时间和业务的增长, 你对Mixin的修改越来越多,难以维护
4、拥抱ES6,ES6的class不支持Mixin
Render Props:
是一种剥离重复使用的逻辑代码,提升组件复用性的解决方案
在被复用的组件中,通过一个名为“render”(属性名也可以不是render,只要值是一个函数即可)的属性,该属性是一个函数,这个函数接受一个对象并返回一个子组件,会将这个函数参数中的对象作为props传入给新生成的组件
缺点:无法使用SCU做优化。
HOC:
高阶组件(HOC)是react中的高级技术,用来重用组件逻辑。
hook:
React Hooks是React 16.7.0-alpha版本推出的新特性,目的是解决React的状态共享问题。称之为状态共享可能描述的并不是很恰当,称为状态逻辑复用可能会更恰当,因为React Hooks只共享数据处理逻辑,并不会共享数据本身
本质是把这种面向生命周期编程变成了面向业务逻辑编程,你不用再去关心本不该关心的生命周期。
use 前缀标识的,为了不弄错每个盒子和状态的对应关系,书写的时候 Hooks 需要 use 开头且放在顶层作用域,即不可以包裹 if/switch/when/try 等。
有了 hooks 加持之后,函数组件具备了状态管理,除了可以使用内置的 hooks ,我们还可以自定义 hooks。
内置hooks:
所谓的自定义Hook,其实就是指函数名以use开头并调用其他Hook的函数,自定义Hook的每个状态都是完全独立的。
栗子:
import React, { useState } from 'react';
function Hook() {
const [count, setCount] = useState(0);
return (
You clicked {count} times
<button onClick={() => setCount(count + 1)}>
Click me
);
}
useState是react自带的一个hook函数,它的作用就是用来声明状态变量。
useState**:**
用来承担与类组件中的 state 一样的作用,组件内部的状态管理。
useEffect**:**
可以用来模拟生命周期,即可以完成某些副作用。
useContext**:**
专门为函数组件提供的 context hook API,可以更加方便地获取 context 的值。
useMemo**:**
useMemo 用于缓存一些耗时的计算结果(返回值),只有当依赖项改变时才重新进行计算。
useCallback**:**
它的本质是对函数依赖进行分析,依赖变更时才重新执行。
React hooks 有什么优势?
1. 不需要基于类的组件、生命周期钩子和 this 关键字
2. 通过将公共函数抽象到定制钩子中,使重用逻辑变得更容易
3. 通过能够将逻辑与组件本身分离出来,使代码更具可读性和可测试性
4. 借助于React提供的Hooks API,函数组件可以实现绝大部分的类组件功能,并且Hooks在共享状态逻辑、提高组件复用性上也具有一定的优势。可以预见的是,Hooks将是React未来发展的重要方向
React 的 Fiber 架构
React16启用了全新的架构,叫做Fiber,**是一种基于浏览器的单线程调度算法,**其最大的使命是解决大型React项目的性能问题,再顺手解决之前的一些痛点。
痛点:
1、组件不能返回数组。
2、弹窗问题
3、异常处理
react fiber 使用了 2 个核心解决思想:
让渲染有优先级
可中断 React Fiber 将虚拟 DOM 的更新过程划分两个阶段,reconciler 调和阶段与 commit 阶段. 看下图:
React 性能优化
类组件中的优化手段
1、使用纯组件 PureComponent 作为基类。
2、使用 React.memo 高阶函数包装组件。
3、使用 shouldComponentUpdate 生命周期函数来自定义渲染逻辑,提高 diff 的性能。
方法组件中的优化手段
1、使用 useMemo。
2、使用 useCallBack。
其他方式
1、在列表需要频繁变动时,使用唯一 id 作为 key,而不是数组下标。
2、必要时通过改变 CSS 样式隐藏显示组件,而不是通过条件判断显示隐藏组件。
3、使用 Suspense 和 lazy 进行懒加载,例如:
说说你用react有什么坑点?
JSX 做表达式判断时候,需要强转为boolean类型
尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃
遍历子节点的时候,不要用 index 作为组件的 key 进行传入
react的优势以及特点?
优势
实现对虚拟DOM的操作,使得它速度快,提高了Web性能
组件化,模块化。react里每一个模块都是一个组件,组件化开发,可维护性高
单向数据流,比较有序,有便于管理,它随着React视图库的开发而被 Facebook 概念化
跨浏览器兼容:虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的 API,甚至在 IE8 中都是没问题的
不足
react中只是 MVC 模式的View部分,要依赖引入很多其他模块开发
当父组件进行重新渲染操作时,即使子组件的props或state没有做出任何改变,也会同样进行重新渲染
特点
声明式设计:React采用声明范式,可以轻松描述应用
高效:React通过对DOM的模拟,最大限度地减少与DOM的交互
灵活:React可以与已知的库或框架很好地配合
React 的 diff 算法工作过程
1. 把树形结构按照层级分解,只比较同级元素。
2. 列表结构的每个单元添加唯一的 key 属性,方便比较。
3. React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
4. 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty 到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
5. 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
react的diff算法用在什么地方呢?
当组件更新的时候,react会创建一个新的虚拟dom树并且会和之前储存的dom树进行比较,这个比较的过程就用到了diff算法