-
讲一下React的Fiber架构?
React Fiber 是 React 16 中新增的一种调度算法,主要用于实现对组件的增量渲染(递增渲染)。它采用了浏览器的 requestIdleCallback API,在主线程有空闲时间时安排任务,可以让 React 在长时间运行任务时,中断执行去响应用户的交互,然后在稍后继续下一步渲染工作。这样有效提高了应用程序的响应速度。
-
增量渲染:实现了任务拆分,将任务拆分为一小块一小块的单元,每次只执行一小部分任务后释放控制权交还给主线程,避免长时间占用主线程。
-
优先级调度:React Fiber 引入了任务优先级的概念,不同类型的更新有不同的优先级,通过这种方式,React 可以在主线程空闲时处理优先级较低的任务,优先级较高的任务则可以立即执行,从而优化用户体验
-
并发模式:React Fiber 开启了 React 的并发模式(Concurrent Mode)的可能,使得 React 可以在同一时间处理多个状态的更新,根据优先级决定先处理哪个。 错误边界处理:
Fiber Reconciler(也就是 Fiber)采用了“时间分片”策略,使得渲染过程可以被打断,变得可控,并且可以优先执行紧急任务。例如,当用户点击按钮时,React 会暂停正在进行的渲染工作,先执行这个更为紧急的任务,然后再去完成原来的工作。
以下是 Fiber 原理的主要部分:
-
Fiber 节点:每个 React 组件都有一个或多个 fiber 节点与之对应。它是一个普通的 JavaScript 对象,保存了组件的类型(函数组件、类组件等)、当前状态和其它信息。
-
双缓存:Fiber 为每个节点创建了一个副本,一个用于显示(current Fiber),另一个用于在内存中进行计算(workInProgress Fiber)。它们分别代表了节点的两个状态:当前屏幕上的状态和下一帧的新状态。
-
链表遍历:Fiber 构建了一种链表的数据结构来描述组件树。这样在遍历更新组件树时,可以灵活地暂停、继续和重启,并且可以优先处理优先级较高的更新。
-
分阶段计算:Fiber 将组件更新任务拆分为两个阶段:Render 阶段和 Commit 阶段。在 Render 阶段,会构建 workInProgress Fiber 树,并找出需要更新的节点,在这个阶段可以打断和重启;Commit 阶段主要将 workInProgress Fiber 树渲染到页面上,这个阶段不能中断。
-
-
说一下 React diff 算法?
两个不同类型的元素将产生不同的树---卸载旧树,构建新树
根据不同的key和props来指示哪些子元素可以在不同的渲染下保持稳定---处理列表项,更精准的移动插入或删除。
运作过程:
a. Tree Diff(主要是为了解决 “节点跨层级移动”): 这个阶段是对树的各个节点进行比较,类型相同则对比更新不同的内容和属性(递归比较子节点);不同类型则卸载旧树,构建新树。 对整个树进行深度优先遍历;
b. Component Diff: 这个阶段是对组件进行比较,组件类型相同则按照原始规则进行setState,然后比较虚拟DOM;若不是则删除该组件及其子组件,重新生成新的组件。
c. Element Diff: 这个阶段主要处理子节点DOM节点的比较,对子节点进行简单的增删改操作,通过唯一的key识别各节点之间的关系,减少节点交替,提高性能。
对比同层级下的子节点集合进行差异对比;通过 key 值进行节点匹配,找出需要被更新、插入和删除的节点。
-
说一下对 React Hook 的理解,它的实现原理,和生命周期有哪些区别?
hooks的实现原理:
React Hook 的实现原理主要通过链表和数组的数据结构来实现的:
a. 在 React 中,每个组件对应一个 fiber 实例,fiber 实例的 memoizedState 属性是一个链表,这个链表用于存储这个组件中所有 Hooks 的状态;
b. 当你在代码中调用 useState 或 useEffect 等 Hook 时,实际上是向这个链表中添加一个节点,这个节点存储了对应 Hook 的状态和其他信息。调用顺序决定了它在链表中的位置
c. 当组件重新渲染时,React 将按照旧的顺序来消费这个链表中的状态,也就是说,先调用的 useState 对应的是链表的前面部分,后面调用的 useState 或 useEffect 对应的则是链表后面的部分。
d. 由于每次渲染都会按照相同的顺序调用 Hook,因此所有的 state 和 effect 总能找到它在链表中的对应位置,进而保证了状态的正确性
e. 对于 useEffect,React 在执行一个 effect 时,并不会立即执行它,而是将它放到一个单独的数据结构中,在所有的组件都渲染完毕之后再统一执行。这使得 React 有能力合理地安排和优化 effect 的执行顺序,以保证性能。
-
React Hook 实现原理中,为什么要依赖 Hooks 的调用顺序?
React 内部会为每一个函数组件维护一份“state 列表”,这个列表中保存了函数组件中每一个 Hook 的状态。保持 Hook 调用顺序的一致,也就意味着 React 能够准确地知道当前操作或获取的 state 对应于哪个 Hook,从而能够保证 state 的正确性。
如果在条件、循环或者嵌套函数中调用 Hook,可能会打破这个固定的调用顺序,React 就失去了确定对应关系的依据,无法正确地获取和更新对应的 state,可能导致一些难以预期的问题。
-
react受控组件和非受控组件
受控组件:受控组件是指输入数据受到 React 组件控制的表单元素。在受控组件中,表单数据由 React 组件的 state 管理,并通过 setState 方法进行更新。这意味着我们可以对输入的数据进行控制,如进行格式化、验证等操作
非受控组件:非受控组件是指输入数据由 DOM 自身处理的表单元素。在非受控组件中,我们并不直接操作表单的数据,当我们需要表单的数据时,我们就从 DOM 中取出。这通常通过 ref 实现。
-
说一下 Redux 的原理,介绍下整体的一个工作流程
Store(状态容器):在 Redux 中,所有的状态都保存在一个单一的对象之中,这个对象就是 store。
Action(行为):Action 是用于描述发生了什么的简单对象。每个 Action 对象必须包含一个 type 属性,用于指定操作的类别。
Reducer(处理函数):Reducer 是根据指定的 Action 更新状态的函数。Reducer函数接收当前的状态和一个 Action,然后返回一个新的状态。
派发 Action -> Reducer 处理 Action -> 生成新的 State -> 触发 Listener。其目标是使得状态更新的过程更加可预测和可追踪
-
React 组件中怎么做事件代理?它的原理是什么?
a. 统一事件监听:为了避免在每个 DOM 节点上都添加事件监听,React 会在 document 根节点上统一添加事件监听,所有的事件都会被统一收集处理。
b. SyntheticEvent 对象:React 中构建了一套 SyntheticEvent 合成事件系统,原生事件发生后,会被 React 接收,然后封装为完全符合 W3C 规范的 SyntheticEvent 对象,并在更新组件时按照事件流(捕获、目标、冒泡阶段)的顺序批量运行。
事件代理的优点包括减少内存消耗,避免频繁的操作真实 DOM 而引发重排重绘,实现动态监听新添加的元素等。
-
柯里化函数?
柯里化是一种将接受多个参数的函数转换为接受单一参数的函数,然后返回接受余下的参数且返回结果的新函数的技术。也可以理解为,柯里化是一种通过减少参数的数量来创建新函数的方式。
好处:参数复用/延迟执行/提前返回/支持管道—通过柯里化,可以创建一个管道。管道就是一系列的函数调用,每个函数的输出是下一个函数的输入。
-
react 异步渲染的概念,介绍 Time Slicing 和 Suspense?
Time Slicing 是指,React 将渲染工作(也就是 virtual dom 的计算工作)分割成小块(chunk),中断和恢复渲染工作。这使得 React 可以将 CPU 和浏览器主线程的掌控权交还给浏览器,使得浏览器可以保持流畅,然后在浏览器空闲的时候,再恢复这些渲染工作。
在新的调度模型下,React 在开始更新组件树时会先估算每个更新的优先级,高优先级的任务(如:用户交互、首次渲染等)会先执行,而低优先级的任务(如setState等)可以被打断,暂停开始执行,然后在浏览器空闲时再继续执行,最大限度地利用了浏览器的空闲时间,从而提高了性能。
Suspense 是 React 用于管理组件异步加载的一种机制。React 16.6 版本引入了 Error Boundaries,这是一个可以捕获其子组件树 JavaScript 异常、记录这些信息并展示备用 UI 的 React 组件。
React Suspense 就是基于同样的理念,但它处理的不是 JavaScript 异常,而是组件的异步加载。
Suspense 可以包裹在任何需要异步加载的组件树最外层,并提供一个 loading fallback 的 UI,当组件树中的任何一个组件未完成加载时就渲染出这个 UI,只有当所有组件都完成加载后,才会渲染真实的 UI。
有了 Suspense,我们就可以非常轻松地为组件添加异步加载的功能,而无需关心复杂的状态管理,大大提高了开发效率。
-
如何解决 props 层级过深的问题?
使用 Context API/redux或者mobx/组件复用
-
渲染十万条数据解决方案?
分页/虚拟列表/懒加载/滚动加载/Web Worker
react 面试题整理
Published: at 01:05 PM