React
参考题目
TODO:
- React Class 组件有哪些周期函数?分别有什么作用?
- React Class 组件中请求可以在 componentWillMount 中发起吗?为什么?
- React Class 组件和 React Hook 的区别有哪些?
- React 中高阶函数和自定义 Hook 的优缺点?
- 简要说明 React Hook 中 useState 和 useEffect 的运行原理?
- useReducers 与 redux 是什么关系?
- React 如何发现重渲染、什么原因容易造成重渲染、如何避免重渲染?
- React Hook 中 useEffect 有哪些参数,如何检测数组依赖项的变化?
- React 的 useEffect 是如何监听数组依赖项的变化的?
- React Hook 和闭包有什么关联关系?
- React 中 useState 是如何做数据初始化的?
- 列举你常用的 React 性能优化技巧?
- React 有什么特点?
- 列出 React 的一些主要优点。
- React 有哪些限制?
- 什么是 JSX?
- 你了解 Virtual DOM 吗?解释一下它的工作原理。
- 与 ES5 相比,React 的 ES6 语法有何不同?
- 解释 React 中 render() 的目的。
- React 中的状态是什么?它是如何使用的?
- 如何更新组件的状态?
- 如何模块化 React 中的代码?
- React 中的事件是什么?
- 如何在 React 中创建一个事件?
- 你对 React 的 refs 有什么了解?
- 列出一些应该使用 Refs 的情况。
- 如何在 React 中创建表单
- 什么是高阶组件(HOC)?
- MVC 框架的主要问题是什么?
- Redux 与 Flux 有何不同?
- 数据如何通过 Redux 流动?
- 什么是 React 路由?
- 为什么 React Router v4 中使用 switch 关键字?
- React 的实现原理
- 说一下 React 生命周期?
- React 16, 17, 18 的变化
- React Class 组件有哪些周期函数?分别有什么作用?
- React Class 组件中请求可以在 componentWillMount 中发起吗?为什么
- React Class 组件和 React Hook 的区别有哪些
- React 中高阶函数和自定义 Hook 的优缺点
- 简要说明 React Hook 中 useState 和 useEffect 的运行原理
- React 如何发现重渲染、什么原因容易造成重渲染、如何避免重渲染
- React Hook 中 useEffect 有哪些参数,如何检测数组依赖项的变化
- React 的 useEffect 是如何监听数组依赖项的变化的
- React Hook 和闭包有什么关联关系
- React 中 useState 是如何做数据初始化的
- 列举你常用的 React 性能优化技巧
- React 代码层的优化可以说一下吗?
- 说一下
useMemo
和useCallback
有什么区别? - 说一下
useEffect
和useLayoutEffect
有什么区别? useEffect
对应在class
中的生命周期怎么写?- 如果在 if 里面写
useEffect
会有什么表现? - 说一下 React 的
Fiber
架构是什么? - 什么是 fiber,fiber 解决了什么问题
- Fiber 的可中断、可恢复怎么实现的
- Fiber 更新机制
- 双缓冲模式
- React 渲染流程
- 写 React/Vue 项目时,为什么要在列表组件中写 key,其作用是什么?
- React 中 setState 是同步的还是异步的?为什么
- setState 实现原理
- Virtual DOM 真的比操作原生 DOM 快吗?谈谈你的想法
- react-router 里面的
<Link>
标签和<a>
标签有什么区别?如何禁用掉<a>
标签默认事件,禁用掉之后如何实现跳转? - React 和 Vue 的 diff 时间复杂度从 O(n^3) 优化到 O(n), 那么 O(n^3) 和 O(n) 是如何计算出来的?
- 为什么在文件中没有使用 react,也要在文件顶部
import React from 'react'
? - 为什么 React 自定义组件首字母要大写?
- React 组件为什么不能返回多个元素?
- React 中元素和组件的区别
- React 事件机制,什么是合成事件
- DOM 事件流是怎么工作的,一个页面往往会绑定多个事件,页面接收事件的顺序叫事件流
- HOC 和 hooks 的区别
- React 性能优化手段
- react 组件通信方式有哪些
- React hooks 解决了什么问题,有什么优缺点
- 函数组件与类组件的区别
- 在 React 中如何识别一个表单项里的表单做到了最小粒度/代价的渲染?
- 在 React 的开发的过程中你能想到哪些控制渲染成本的方法?
- React diff 算法
- React 中的时间切片
- React Hooks 及应用场景
- React Hooks 原理
- 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
会捕获 props
和 state
。所以即便在回调函数里,你拿到的还是初始的 props
和 state
。
如果想得到“最新”的值,可以使用 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 算法做了哪些妥协呢?,参考如下:
- tree diff:只对比同一层的 dom 节点,忽略 dom 节点的跨层级移动
- component diff:如果不是同一类型的组件,会删除旧的组件,创建新的组件
- element diff:对于同一层级的一组子节点,需要通过唯一 id 进行来区分
调用 setState 之后发生了什么?
- 在 setState 的时候,React 会为当前节点创建一个 updateQueue 的更新列队。
- 然后会触发 reconciliation 过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树,Fiber 算法的最大特点是可以做到异步可中断的执行。
- 然后 React Scheduler 会根据优先级高低,先执行优先级高的节点,具体是执行 doWork 方法。
- 在 doWork 方法中,React 会执行一遍 updateQueue 中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。
- 当前节点 doWork 完成后,会执行 performUnitOfWork 方法获得新节点,然后再重复上面的过程。
- 当所有节点都 doWork 完成后,会触发 commitRoot 方法,React 进入 commit 阶段。
- 在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素。
为什么虚拟 dom 会提高性能?
虚拟 dom 相当于在 JS 和真实 dom 中间加了一个缓存,利用 diff 算法避免了没有必要的 dom 操作,从而提高性能。
错误边界是什么?它有什么用?
在 React 中,如果任何一个组件发生错误,它将破坏整个组件树,导致整页白屏。这时候我们可以用错误边界优雅地降级处理这些错误。
什么是 Portals?
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
React 组件间有那些通信方式?
- 父组件向子组件通信
- 通过 props 传递
- 子组件向父组件通信
- 主动调用通过 props 传过来的方法,并将想要传递的信息,作为参数,传递到父组件的作用域中
- 跨层级通信
- 使用 react 自带的 Context 进行通信,createContext 创建上下文,useContext 使用上下文。
- 使用 Redux 或者 Mobx 等状态管理库
- 使用订阅发布模式
React 父组件如何调用子组件中的方法?
- 如果是在函数组件中调用子组件(>= react@16.8),可以使用
useRef
和useImperativeHandle
- 如果是在类组件中调用子组件(>= react@16.4),可以使用
createRef
React 有哪些优化性能的手段?
- 类组件中的优化手段
- 使用纯组件 PureComponent 作为基类。
- 使用 React.memo 高阶函数包装组件。
- 使用 shouldComponentUpdate 生命周期函数来自定义渲染逻辑。
- 函数组件中的优化手段
- 使用 useMemo。
- 使用 useCallBack。
- 其他方式
- 在列表需要频繁变动时,使用唯一 id 作为 key,而不是数组下标。
- 必要时通过改变 CSS 样式隐藏显示组件,而不是通过条件判断显示隐藏组件。
- 使用 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 有哪些异步中间件?
- redux-thunk 可以理解为 redux-function,让 dispatch 支持函数
- redux-saga 借助 JS 的 generator 来处理异步,避免了回调的问题
- redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件
- redux-observable 借助了 RxJS 流的思想以及其各种强大的操作符,来处理异步问题
- reselect 计算衍生状态、派生数据 (computer)
redux
- redux 工作原理
- redux 中的 reducer 为什么必须 (最好) 是纯函数?
- 前端路由解决了什么问题
- react-router-dom 有哪些组件
参考: