Skip to content
大纲

React

参考题目

TODO:

  1. React Class 组件有哪些周期函数?分别有什么作用?
  2. React Class 组件中请求可以在 componentWillMount 中发起吗?为什么?
  3. React Class 组件和 React Hook 的区别有哪些?
  4. React 中高阶函数和自定义 Hook 的优缺点?
  5. 简要说明 React Hook 中 useState 和 useEffect 的运行原理?
  6. useReducers 与 redux 是什么关系?
  7. React 如何发现重渲染、什么原因容易造成重渲染、如何避免重渲染?
  8. React Hook 中 useEffect 有哪些参数,如何检测数组依赖项的变化?
  9. React 的 useEffect 是如何监听数组依赖项的变化的?
  10. React Hook 和闭包有什么关联关系?
  11. React 中 useState 是如何做数据初始化的?
  12. 列举你常用的 React 性能优化技巧?
  13. React 有什么特点?
  14. 列出 React 的一些主要优点。
  15. React 有哪些限制?
  16. 什么是 JSX?
  17. 你了解 Virtual DOM 吗?解释一下它的工作原理。
  18. 与 ES5 相比,React 的 ES6 语法有何不同?
  19. 解释 React 中 render() 的目的。
  20. React 中的状态是什么?它是如何使用的?
  21. 如何更新组件的状态?
  22. 如何模块化 React 中的代码?
  23. React 中的事件是什么?
  24. 如何在 React 中创建一个事件?
  25. 你对 React 的 refs 有什么了解?
  26. 列出一些应该使用 Refs 的情况。
  27. 如何在 React 中创建表单
  28. 什么是高阶组件(HOC)?
  29. MVC 框架的主要问题是什么?
  30. Redux 与 Flux 有何不同?
  31. 数据如何通过 Redux 流动?
  32. 什么是 React 路由?
  33. 为什么 React Router v4 中使用 switch 关键字?
  34. React 的实现原理
  35. 说一下 React 生命周期?
  36. React 16, 17, 18 的变化
  37. React Class 组件有哪些周期函数?分别有什么作用?
  38. React Class 组件中请求可以在 componentWillMount 中发起吗?为什么
  39. React Class 组件和 React Hook 的区别有哪些
  40. React 中高阶函数和自定义 Hook 的优缺点
  41. 简要说明 React Hook 中 useState 和 useEffect 的运行原理
  42. React 如何发现重渲染、什么原因容易造成重渲染、如何避免重渲染
  43. React Hook 中 useEffect 有哪些参数,如何检测数组依赖项的变化
  44. React 的 useEffect 是如何监听数组依赖项的变化的
  45. React Hook 和闭包有什么关联关系
  46. React 中 useState 是如何做数据初始化的
  47. 列举你常用的 React 性能优化技巧
  48. React 代码层的优化可以说一下吗?
  49. 说一下 useMemouseCallback 有什么区别?
  50. 说一下 useEffectuseLayoutEffect 有什么区别?
  51. useEffect 对应在 class 中的生命周期怎么写?
  52. 如果在 if 里面写 useEffect 会有什么表现?
  53. 说一下 React 的 Fiber 架构是什么?
  54. 什么是 fiber,fiber 解决了什么问题
  55. Fiber 的可中断、可恢复怎么实现的
  56. Fiber 更新机制
  57. 双缓冲模式
  58. React 渲染流程
  59. 写 React/Vue 项目时,为什么要在列表组件中写 key,其作用是什么?
  60. React 中 setState 是同步的还是异步的?为什么
  61. setState 实现原理
  62. Virtual DOM 真的比操作原生 DOM 快吗?谈谈你的想法
  63. react-router 里面的 <Link> 标签和 <a> 标签有什么区别?如何禁用掉 <a> 标签默认事件,禁用掉之后如何实现跳转?
  64. React 和 Vue 的 diff 时间复杂度从 O(n^3) 优化到 O(n), 那么 O(n^3) 和 O(n) 是如何计算出来的?
  65. 为什么在文件中没有使用 react,也要在文件顶部 import React from 'react'
  66. 为什么 React 自定义组件首字母要大写?
  67. React 组件为什么不能返回多个元素?
  68. React 中元素和组件的区别
  69. React 事件机制,什么是合成事件
  70. DOM 事件流是怎么工作的,一个页面往往会绑定多个事件,页面接收事件的顺序叫事件流
  71. HOC 和 hooks 的区别
  72. React 性能优化手段
  73. react 组件通信方式有哪些
  74. React hooks 解决了什么问题,有什么优缺点
  75. 函数组件与类组件的区别
  76. 在 React 中如何识别一个表单项里的表单做到了最小粒度/代价的渲染?
  77. 在 React 的开发的过程中你能想到哪些控制渲染成本的方法?
  78. React diff 算法
  79. React 中的时间切片
  80. React Hooks 及应用场景
  81. React Hooks 原理
  82. HOC 高阶组件原理及使用场景

React 面试题

setState 是异步还是同步?

  • 合成事件中是异步
  • 钩子函数中的是异步
  • 原生事件中是同步
  • setTimeout 中是同步

在 React 中,如果是由 React 引发的事件处理(比如通过 onClick 引发的事件处理),调用 setState 不会同步更新 this.state,除此之外的 setState 调用会同步执行 this.state。所谓“除此之外”,指的是绕过 React 通过 addEventListener 直接添加的事件处理函数,还有通过 setTimeout/setInterval 产生的异步调用。

原因:在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中回头再说,而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,但是,有一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,而当 React 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步更新 this.state

注意:setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的 callback 拿到更新后的结果。

详细请看 深入 setState 机制

聊聊 react 的生命周期

版本有差异,差异是什么?

参见 react 生命周期

useEffect(fn, []) 和 componentDidMount 有什么差异?

useEffect 会捕获 propsstate。所以即便在回调函数里,你拿到的还是初始的 propsstate

如果想得到“最新”的值,可以使用 ref

hooks 为什么不能放在条件判断里?

以 setState 为例,在 react 内部,每个组件 (Fiber) 的 hooks 都是以链表的形式存在 memoizeState 属性中

update 阶段,每次调用 setState,链表就会执行 next 向后移动一步。如果将 setState 写在条件判断中,假设条件判断不成立,没有执行里面的 setState 方法,会导致接下来所有的 setState 的取值出现偏移,从而导致异常发生。

聊一聊 diff 算法

传统 diff 算法的时间复杂度是 O(n^3),这在前端 render 中是不可接受的。为了降低时间复杂度,react 的 diff 算法做了一些妥协,放弃了最优解,最终将时间复杂度降低到了 O(n)。

那么 react diff 算法做了哪些妥协呢?,参考如下:

  1. tree diff:只对比同一层的 dom 节点,忽略 dom 节点的跨层级移动
  2. component diff:如果不是同一类型的组件,会删除旧的组件,创建新的组件
  3. element diff:对于同一层级的一组子节点,需要通过唯一 id 进行来区分

调用 setState 之后发生了什么?

  1. 在 setState 的时候,React 会为当前节点创建一个 updateQueue 的更新列队。
  2. 然后会触发 reconciliation 过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树,Fiber 算法的最大特点是可以做到异步可中断的执行。
  3. 然后 React Scheduler 会根据优先级高低,先执行优先级高的节点,具体是执行 doWork 方法。
  4. 在 doWork 方法中,React 会执行一遍 updateQueue 中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。
  5. 当前节点 doWork 完成后,会执行 performUnitOfWork 方法获得新节点,然后再重复上面的过程。
  6. 当所有节点都 doWork 完成后,会触发 commitRoot 方法,React 进入 commit 阶段。
  7. 在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素。

为什么虚拟 dom 会提高性能?

虚拟 dom 相当于在 JS 和真实 dom 中间加了一个缓存,利用 diff 算法避免了没有必要的 dom 操作,从而提高性能。

错误边界是什么?它有什么用?

在 React 中,如果任何一个组件发生错误,它将破坏整个组件树,导致整页白屏。这时候我们可以用错误边界优雅地降级处理这些错误。

什么是 Portals?

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。

tsx
ReactDOM.createPortal(child, container)

React 组件间有那些通信方式?

  1. 父组件向子组件通信
    1. 通过 props 传递
  2. 子组件向父组件通信
    1. 主动调用通过 props 传过来的方法,并将想要传递的信息,作为参数,传递到父组件的作用域中
  3. 跨层级通信
    1. 使用 react 自带的 Context 进行通信,createContext 创建上下文,useContext 使用上下文。
    2. 使用 Redux 或者 Mobx 等状态管理库
    3. 使用订阅发布模式

React 父组件如何调用子组件中的方法?

  • 如果是在函数组件中调用子组件(>= react@16.8),可以使用 useRefuseImperativeHandle
  • 如果是在类组件中调用子组件(>= react@16.4),可以使用 createRef

React 有哪些优化性能的手段?

  1. 类组件中的优化手段
    1. 使用纯组件 PureComponent 作为基类。
    2. 使用 React.memo 高阶函数包装组件。
    3. 使用 shouldComponentUpdate 生命周期函数来自定义渲染逻辑。
  2. 函数组件中的优化手段
    1. 使用 useMemo。
    2. 使用 useCallBack。
  3. 其他方式
    1. 在列表需要频繁变动时,使用唯一 id 作为 key,而不是数组下标。
    2. 必要时通过改变 CSS 样式隐藏显示组件,而不是通过条件判断显示隐藏组件。
    3. 使用 Suspense 和 lazy 进行懒加载

为什么 React 元素有一个 $$typeof 属性?

目的是为了防止 XSS 攻击。因为 Symbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。

如果没有 $$typeof 这个属性,react 会拒绝处理该元素。

React 如何区分 Class 组件 和 Function 组件?

React 区分 Class 组件 和 Function 组件的方式很巧妙,由于所有的类组件都要继承 React.Component,所以只要判断原型链上是否有 React.Component 就可以了

HTML 和 React 事件处理有什么区别?

  • 在 HTML 中事件名必须小写,而在 React 中需要遵循驼峰写法
  • 在 HTML 中可以返回 false 以阻止默认的行为,而在 React 中必须地明确地调用 preventDefault()

什么是 suspense 组件?

  • Suspense 让组件“等待”某个异步操作,直到该异步操作结束即可渲染。
  • Suspense 也可以用于懒加载

为什么 JSX 中的组件名要以大写字母开头?

因为 React 要知道当前渲染的是组件还是 HTML 元素。

redux 是什么?

Redux 是一个为 JavaScript 应用设计的,可预测的状态容器。

它解决了如下问题:

  • 跨层级组件之间的数据传递变得很容易
  • 所有对状态的改变都需要 dispatch,使得整个数据的改变可追踪,方便排查问题。

但是它也有缺点:

  • 概念偏多,理解起来不容易
  • 样板代码太多

react-redux 的实现原理?

通过 redux 和 react context 配合使用,并借助高阶函数,实现了 react-redux。

redux 异步中间件有什么作用?

抽取逻辑以复用

redux 有哪些异步中间件?

  1. redux-thunk 可以理解为 redux-function,让 dispatch 支持函数
  2. redux-saga 借助 JS 的 generator 来处理异步,避免了回调的问题
    1. redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件
  3. redux-observable 借助了 RxJS 流的思想以及其各种强大的操作符,来处理异步问题
  4. reselect 计算衍生状态、派生数据 (computer)

redux

  1. redux 工作原理
  2. redux 中的 reducer 为什么必须 (最好) 是纯函数?
  3. 前端路由解决了什么问题
  4. react-router-dom 有哪些组件

参考: