本篇文章会列举 react 的全部常见面试问题. 并附上详细解答.若是你想更深刻的了解底层原理, 可到文末的建议阅读中查找.javascript
详细的内容请见另外一篇文章: 面试官: 谈一谈 HOC、Render props、Hookshtml
在 React 中, React 会先将代码转换成一个 JS 对象, 而后再将这个 JS 对象转换成真正的 DOM. 这个 JS 对象就是所谓的虚拟 DOM.java
它可让咱们无须关注 DOM 操做, 只须要开心地编写数据,状态便可.react
为何是 O(n^3) ? 从一棵树转化为另一棵树,直观的方式是用动态规划,经过这种记忆化搜索减小时间复杂度。因为树是一种递归的数据结构,所以最简单的树的比较算法是递归处理。确切地说,树的最小距离编辑算法的时间复杂度是 O(n^2m(1+logmn)), 咱们假设 m 与 n 同阶, 就会变成 O(n^3)。git
为何是 O(n^3)github
react diff 原理面试
简单的来说, react 它只比较同一层, 一旦不同, 就删除. 这样子每个节点只会比较一次, 因此算法就变成了 O(n).算法
对于同一层的一组子节点. 他们有可能顺序发生变化, 可是内容没有变化. react 根据 key 值来进行区分, 一旦 key 值相同, 就直接返回以前的组件, 不从新建立.数组
这也是为何渲染数组的时候, 没有加 key 值或者出现重复key值会出现一些奇奇怪怪的 bug .浏览器
除了 key , 还提供了选择性子树渲染。开发人员能够重写 shouldComponentUpdate 提升 diff 的性能。
<div>Hello ConardLi</div>
复制代码
实际上, babel 帮咱们将这个语法转换成
React.createElement('div', null, `Hello ConardLi`)
复制代码
自定义组件必须大写的缘由. babel 在编译的过程当中会判断 JSX 组件的首字母, 若是是小写, 则为原生 DOM 标签, 就编译成字符串. 若是是大写, 则认为是自定义组件. 编译成对象.
为何如下代码会报错?
return (<a></a><a></a>)
复制代码
一样的, 由于咱们是按照 React.createElement() 来建立组件, 因此只能有一个根节点. 若是你想要使用 2 个平行的节点, 能够用 <></> 来包裹. <></> 会被编译成 <React.Fragment/>.
babel 转译以下:
本身动手玩一下转换, 加深印象吧~
这里的“异步”不是说异步代码实现. 而是说 react 会先收集变动,而后再进行统一的更新.
setState 在原生事件和 setTimeout 中都是同步的. 在合成事件和钩子函数中是异步的.
在 setState 中, 会根据一个 isBatchingUpdates 判断是直接更新仍是稍后更新, 它的默认值是 false. 可是 React 在调用事件处理函数以前会先调用 batchedUpdates 这个函数, batchedUpdates 函数 会将 isBatchingUpdates 设置为 true. 所以, 由 react 控制的事件处理过程, 就变成了异步(批量更新).
咱们先看看 冒泡捕获 的经典图:
在组件挂载的阶段, 根据组件生命的 react 事件, 给 document 添加事件 addEventListener, 并添加统一的事件处理函数 dispatchEvent.
将全部的事件和事件类型以及 react 组件进行关联, 将这个关系保存在一个 map 里. 当事件触发的时候, 首先生成合成事件, 根据组件 id 和事件类型找到对应的事件函数, 模拟捕获流程, 而后依次触发对应的函数.
若是原生事件使用 stopPropagation 阻止了冒泡, 那么合成事件也被阻止了.
React 事件机制跟原生事件有什么区别 React 的事件使用驼峰命名, 跟原生的所有小写作区分. 不能经过 return false 来阻止默认行为, 必须明确调用 preventDefault 去阻止浏览器的默认响应.
背景: 因为浏览器它将 GUI 描绘,时间器处理,事件处理,JS 执行,远程资源加载通通放在一块儿。若是执行 js 的更新, 占用了过久的进程就会致使浏览器的动画没办法执行,或者 input 响应比较慢。
react fiber 使用了 2 个核心解决思想:
一次更新过程会分为不少个分片完成, 因此可能一个任务尚未执行完, 就被另外一个优先级更高的更新过程打断, 这时候, 低优先级的工做就彻底做废, 而后等待机会重头到来.
requestIdleCallback
首先 react 会根据任务的优先级去分配各自的过时时间 expriationTime . requestIdleCallback 在每一帧的多余时间(黄色的区域)调用. 调用 channel.port1.onmessage , 先去判断当前时间是否小于下一帧时间, 若是小于则表明咱们有空余时间去执行任务, 若是大于就去执行过时任务,若是任务没过时. 这个任务就被丢到下一帧执行了.
因为 requestIdleCallback 的兼容性问题, react 本身实现了一个 requestIdleCallback
事实上, 这并不算是 react 的问题, 而是 this 的问题. 可是也是 react 中常常出现的问题. 所以也讲一下
<button type="button" onClick={this.handleClick}>Click Me</button>
复制代码
这里的 this . 当事件被触发且调用时, 由于 this 是在运行中进行绑定的.his 的值会回退到默认绑定,即值为 undefined,这是由于类声明和原型方法是以严格模式运行。
咱们可使用 bind 绑定到组件实例上. 而不用担忧它的上下文.
由于箭头函数中的 this 指向的是定义时的 this,而不是执行时的 this. 因此箭头函数一样也能够解决.