Skip to content
MiTu

MiTu

A Web developer who loves to Reading and photography

React FAQ

对 react 的理解

题目

谈谈对 react 的理解

参考答案

详见 React 基础

react 组件之间如何通信

题目

React 组件之间如何通信

参考答案

父子组件通信可以通过下面 3 种方法通信

  1. 父组件给子组件传递 props 数据
  2. 子组件回调父组件传的方法
  3. 父组件通过 ref 获得子组件的引用,调用子组件的方法

兄弟组件可以通过 2 种方法通信

  1. 事件总线
  2. 状态管理工具(redux、mobx)

setState 原理

题目

setState 原理,它是如何实现状态更改的?

参考答案

详见 setState

react 的 context

题目

介绍一下 react 的 context

参考答案

详见 context

react 列表的 key

题目

react 的列表中为什么需要 key 属性?

key 属性如果赋值为数组的 index,会有什么问题吗?

参考答案

不加 key 或者 key 使用 index 赋值,都会列表变动后导致 React 无法辨别 item 前后的对应关系。

这可能带来两种问题:

  1. 性能损耗,因为无法正确识别列表中元素变化,可能做一些多余的更新属性的操作,造成性能损失。
  2. 非受控的表单的值不符合预期,因为无法正确识别列表中元素变化,对于非受控的表单,React 无法知道表单的变化,也就没法正确地更新其值。

react diff 算法

题目

讲一下 react 的 diff 算法

参考答案

详见 diff 算法和 key 的作用

React 的 diff 算法基于两个假设:

1、不同元素的类型会产生不同的树

2、开发者可以通过 key prop 标识一个元素在不同的渲染下可以保持稳定(及相同 key 的元素不需要更新整个元素,不同的 key 需要更新整个元素)

基于上述假设,React 认为在视图更新前后,如果两个节点的 Tag 名(对于原生标签)或者组件(对于自定义组件)相同,则它们是同一个节点,而且如果是不同的根节点,那么子节点也不需要对比,直接用新树替换掉旧的树即可。

对比的过程

1、当一个组件触发更新(setState),则 React 会 diff 以这个组件为根节点的整个虚拟 DOM 树,对比更新后的虚拟 DOM 和更新前的虚拟 DOM。

2、如果两个节点不同,则用新的节点替换掉旧的节点;如果两个节点相同(假设为 oldNode 和 newNode),则对比它们的属性、innerText 和子节点。

3、如果 oldNode 有某个子节点 someOldChild,而 newNode 没有这个子节点(即 newNode 没有一个子节点,和 someOldNode 有相同的 tag 名、自定义组件引用或者 key 值),则删掉 someOldChild;如果 newNode 有某个子节点 somNewChild,而 oldNode 没有,则添加 someNewChild;如果 oldNode 和 newNode 都有某个节点 someChild,则将其移动到正确的位置,并递归地进行对比工作,即以 someChild 为根节点对比新旧两棵虚拟 DOM 树。

从上面的对比过程可以看出,React 的 diff(其实 Vue 也是一样)并不会考虑到节点跨层移动的情况,因此有些观点认为 React 的对比过程可以描述为“按层比较”(level by level)。

react 的 hook

题目

react hook 的好处和限制是什么?

参考答案

hook 是 react 提供的一类 API,它给函数式组件增加状态和逻辑,并将功能代码聚合在一起。

hook 好处是能够让不同功能代码更聚合,更好维护。

限制是:

  1. 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  2. 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中)

题目

说一下常用的 hook 的使用方法和应用场景

参考答案

useState

在函数式组件中添加状态需要使用useState这个hook

useEffect

在函数式组件中添加一些有副作用的操作(如网络请求、操作DOM、绑定事件回调),需要用到useEffect这个hook。

useMemo

useMemo的作用类似于Vue中的computed,会缓存计算结果,只有当依赖的数据改变时候,才会执行其中的计算方法。

useCallback

一般用于生成事件处理函数,防止每次生成新的函数,导致不必要的子组件重新render。场景是计算属性和注册回调。

useRef

useRef可以用来实现获取一个原生DOM或者子组件实例的引用,本质上,它可以用来保存任何可变值。

题目

useState 和 userRef 怎么用?useState 如何实现的?

参考答案

useState 可以给函数式组件添加状态

  1. useState 函数接收一个参数作为初始值

  2. useState 返回值为一个数组,数组第一个元素是状态变量,第二个元素是设置该状态的方法

  3. 调用设置状态的方法,会同步触发 diff 和更新操作

useRef 可以用来实现获取一个原生 DOM 或者子组件实例的引用,本质上,它可以用来保存任何可变值。

  1. useRef 接收一个参数作为初始值。

  2. useRef 返回一个对象,这个对象包含一个 current 属性,这个 current 属性会被初始化为初始值,并且可以更改。

  3. 每次调用渲染函数,都返回同一个对象。

useState 工作的过程如下:

  1. 首次调用函数组件,执行 useState,React 获取到当前正在遍历的节点,创建_state 对象挂载到节点上,根据调用 useState 的顺序,在数组中加入状态,并根据传入的初始值初始化状态。

  2. 当调用状态的 set 方法时候,React 修改_state 上面的状态,并更新相应的组件。

  3. 后面再调用函数组件时候,useState 找到对应的节点的_state,并根据 useState 的调用顺序,找到修改后的状态返回,这样组件就可以拿到正确的状态了。