setState 是异步还是同步?
合成事件中是异步
钩子函数中的是异步
原生事件中是同步
setTimeout中是同步
调用 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 中,如果任何一个组件发生错误,它将破坏整个组件树,导致整页白屏。这时候我们可以用错误边界优雅地降级处理这些错误。
React 组件间有那些通信方式?
详细解答请参照组件的通信方式
-
父组件向子组件通信
通过props
传递 -
子组件向父组件通信
主动调用通过 props 传过来的方法,并将想要传递的信息,作为参数,传递到父组件的作用域中 -
使用 react 自带的
Context
进行通信,createContext
创建上下文,useContext
使用上下文。
React 父组件如何调用子组件中的方法?
- 如果是在方法组件中调用子组件(>= react@16.8),可以使用
useRef
和useImperativeHandle
- 如果是在类组件中调用子组件(>= react@16.4),可以使用
createRef
浅谈组件的生命周期
请移步----->生命周期
React有哪些优化性能的手段
详细解答请跳转---->组件的性能优化
类组件中的优化手段
-
使用纯组件
PureComponent
作为基类。 -
使用
React.memo
高阶函数包装组件。 -
使用
shouldComponentUpdate
生命周期函数来自定义渲染逻辑。
方法组件中的优化手段
-
使用 useMemo。
-
使用 useCallBack。
其他方式
-
在列表需要频繁变动时,使用唯一 id 作为 key,而不是数组下标。
-
必要时通过改变 CSS 样式隐藏显示组件,而不是通过条件判断显示隐藏组件。
-
使用
Suspense
和lazy
进行懒加载
React 如何区分 Class组件 和 Function组件?
一般的方式是借助typeof
和 Function.prototype.toString
来判断当前是不是 class,但是这个方式有它的局限性,因为如果用了 babel 等转换工具,将 class 写法全部转为 function 写法,上面的判断就会失效。
function isClass(func) {
return typeof func === 'function'
&& /^class\s/.test(Function.prototype.toString.call(func));
}
React 区分 Class组件 和 Function组件的方式很巧妙,由于所有的类组件都要继承 React.Component,所以只要判断原型链上是否有 React.Component 就可以了
AComponent.prototype instanceof React.Component
HTML 和 React 事件处理有什么区别?
- 在 HTML 中事件名必须小写;而在 React 中需要遵循驼峰写法
- 在 HTML 中可以返回 false 以阻止默认的行为;而在 React 中必须地明确地调用
preventDefault()
为什么 JSX 中的组件名要以大写字母开头?
因为 React 要知道当前渲染的是组件还是 HTML 元素。