2025.8.22发布,2026.2.5更新
一、组件
-
两种:函数组件,类组件
-
Jsx:本质语法糖,编译成React.createELement,编译依赖babel webpack等 babel-preset-react
-
如何使用数据:{}, 条件渲染,列表渲染,key
-
Key的作用: 列表渲染使用。用于唯一标识列表中的元素,帮助 React 高效更新、重排或复用 DOM 节点。当列表变化时,key 能减少不必要的渲染,避免状态错乱(如输入框内容错位)。
-
什么是受控组件,非受控组件?
- 受控组件由 React(或框架)状态完全控制的表单元素
- 非受控组件表单元素的数据由 DOM 自身管理,而非框架状态
-
在React里,到底什么是副作用?: 副作用借用自函数式编程概念,React组件本质是接收props state 计算并返回一段UI,这个过程应该是纯粹的,除了这个过程其他和外界交互的事情都叫副作用。(storage,settimeout, 请求,console.log,手动改dom等)
二、Hooks
- React hooks解决了什么问题?
- Hooks解决逻辑复用难题,能按逻辑相关性聚合代码,告别生命周期方法导致的碎片化;让你可以在函数组件中使用状态和生命周期特性,赋予函数组件状态管理和副作用处理等核心能力。
- Hooks原理?
- 核心是Hooks链表结构:Hooks链表是微观的,存在于组件内部的,组件之间是独立的。具体来说,每个函数组件对应一个Fiber节点,每个节点有个memoizedState指向自己的hooks链表(单向链表),每个hook(例如useSate)对应链表中的一个节点。首次渲染时会按照调用顺序将hook添加到链表末尾,渲染结束后处理effect。更新渲染时,不要在循环、条件或嵌套函数中调用Hook,因为Hooks链表依赖于调用顺序。React 依赖调用顺序识别 Hook
- 自定义 Hook 本身不是链表节点,它只是一个函数。但自定义 Hook 内部调用的 Hook 会按照调用顺序插入到链表当前位置之后。
- React 内置Hooks有哪些?
- useState, useReducer, useEffect, useLayoutEffect, useMemo, useCallback, useContext, useImperativeHandle, useTransition
- 手动实现一个useState:
- useReducer的用法?和useState区别?
- 用于管理复杂的状态逻辑,特别适合处理多个子状态相互依赖或状态更新逻辑复杂的场景(比如表单、购物车、游戏状态等)。它类似于 Redux 的工作方式,但更轻量且内置在 React 中。
6. useEffect如何使用?第二个参数传不同值执行时机区别?如果在组件卸载前做一些事情?
注意闭包陷阱问题:
注意无限循环问题:
- useEffect, componentDidmount, useLayoutEffect 有什么区别?
- useLayoutEffect: componentDidmount同步版,Dom更新后同步执行,会阻塞渲染。useLayoutEffect近似didmount。
- UseEffect是DOM更新后异步执行。
- Didmount和useEffect不同。Didmount同步执行,会阻塞渲染,useEffect异步执行(微任务)不阻塞渲染。UseEffect比didmount晚一次绘制。但对用户体验差异很小。
- 举个例子:例如同样是在dom挂载后发请求,请求前展示loading,请求数据,setstate渲染这样一个过程:
-
如果是didmount:虚拟到真实dom生成->发请求->首次绘制->请求异步返回->虚拟dom->真实dom->绘制
-
useEffect: 虚拟到真实dom生成 ->首次绘制->发请求->请求异步返回->虚拟dom->真实dom->绘制
-
二者对比:
- useRef如何使用?与useState区别是什么?
- React 用于创建持久化引用对象的 Hook。例如:访问 DOM 元素;跨渲染周期存储可变值
- useMemo useCallback 如何使用?
- useMemo 缓存计算值,useCallback缓存函数。不要过度使用。
- useMemo和React.memo有什么区别?
- React.memo 缓存组件渲染结果,当父组件重渲染时,若子组件的 props 未变化,则跳过子组件的重渲染,提升性能。
- 第一个参数是函数组件,第二个参数可选,是定制比较函数。第二个入如果不传,默认对前后 props 进行浅层比较,相同则复用上次渲染结果。也可以手动定制比较函数(prevProps, nextProps)=> {}
- useContext如何使用?
- 和createContext搭配使用,一个提供数据,一个消费数据。也可以搭配Provider使用。
- useTransition的作用是什么?
- 它的核心作用是区分 “紧急更新” 和 “非紧急更新”,将非紧急的状态更新标记为 “过渡更新”,避免这些更新阻塞用户交互(如输入、点击等紧急操作)。
- 如何自定义hook?举个例子
- setState同步还是异步?
- React 18 前:setState 大部分是异步的,例如在合成事件和生命周期函数中,少量场景下是同步的,例如在 setTimeout/Promise/手写事件中。
- React 18 后:所有场景默认异步批处理,但可通过 flushSync 强制同步。
- React 18 提供 flushSync API 强制立即更新(同步):打断并发渲染。
三、核心机制-虚拟Dom
虚拟DOM,Fiber架构,并发渲染的关系如下:
虚拟DOM是指用JS对象描述UI,与真实DOM解耦,通过比较新旧vDOM树(仅比较同层级节点)确定最小变更,合并多次更新减少DOM操作。工作流程:
虚拟DOM好处:减少昂贵的DOM操作,提升性能;可跨平台,抽象了渲染层 rn ssr通用。
虚拟DOM问题:递归遍历vDOM树是同步不可中断的,当组件树庞大时会导致主线程阻塞(页面卡顿)
四、核心机制-Fiber架构
首先Fiber描述的是从数据更新到渲染DOM这个过程的事情。他涉及虚拟dom diff、中断、调度、恢复等多数流程。
Fiber是React16重构的核心协调算法,它将渲染任务拆解为可中断的细粒度单元。每个React组件对应一个Fiber节点,节点间通过child、sibling和return指针连接成链表,使深度优先遍历变为线性可暂停的过程。React采用双缓存策略,在内存中构建workInProgress树并与当前树交替,实现无闪烁更新。工作流程分为可中断的协调阶段与不可中断的提交阶段,协调阶段对比新旧节点并标记副作用,提交阶段一次性执行DOM更新和副作用。通过时间切片和优先级调度,Fiber让React能暂停低优先级渲染以响应高优先交互,为并发模式奠定基础,最终带来更流畅的用户体验。
Fiber架构的核心在于解决同步渲染的阻塞问题。本质:将同步递归变为异步可中断遍历 .
数据结构上,用链表代替了树结构,实现非递归遍历;引入时间片机制,将渲染任务拆分成了5ms单元在浏览器空闲时间执行。同时采用双缓存机制,后台静默构建完整的 WorkInProgress 树,完成后瞬间切换指针替代当前树,实现无闪烁更新。
React 通过双缓存技术维护两棵 Fiber 树:Current 树,已提交的稳定状态,WorkInProgress 树:内存中构建,可中断修改。
Fiber工作流程:渲染阶段,提交阶段。
Fiber 架构带来的新特性:Suspense,useTransition
深度理解Fiber树,Fiber节点:每个 React 元素:无论是组件还是 DOM 元素,都对应一个 Fiber 节点,节点间有关系指针。
React 为何不直接使用 requestIdleCallback?
- 兼容性与一致性:
requestIdleCallback的浏览器兼容性不理想(当时只有 Chrome 支持较好)2,自行实现可以确保在所有环境中行为一致。 - 性能与可靠性:
requestIdleCallback的触发频率并不高(大约 20 次/秒),且对“空闲时间”的定义和实现可能因浏览器而异,无法满足 React 对高性能和流畅UI的需求6。React 需要更精细、更可控的时间切片。 - 优先级控制:React 需要能够区分不同优先级的更新(比如用户交互的优先级高于预渲染),而
requestIdleCallback本身不提供多种优先级的概念。
React Fiber 并没有直接使用浏览器的 requestIdleCallback,而是吸收其“利用空闲时间”的核心思想,并自行实现了一套功能更强大、更可控的调度机制。
React 的调度机制理解为:
- 时间切片(Time Slicing) :React 将复杂的渲染工作分解成一个个小的工作单元(Fiber节点) 58,并在固定的、短暂的时间片(如5ms)内执行2。
- 中断与恢复:在每个时间片结束后,React 会检查是否有更高优先级的任务(如用户输入、动画)需要处理。如果有,就暂停当前渲染任务,先去处理高优先级任务,等主线程空闲了再回来继续执行之前未完成的渲染任务23。这便是 “可中断渲染” 。
- 调度控制:React 的调度器会自己判断何时该执行、暂停或继续这些任务,而不是完全被动地依赖浏览器报告的空闲时间。
任务总共有多少种优先级?
React 内部的任务优先级管理是一个分层且精细的体系
React 的优先级处理始于事件优先级(如用户点击、滚动等)13。不同紧急程度的事件会触发不同优先级的更新。这些更新会被打上 Lane 标签(更新优先级),然后React会根据这些Lane的优先级来调度任务(任务优先级),最终通过 Scheduler 来执行(调度优先级)
五、核心机制-并发模式
“并发特性”本质上是 React 能够在同一时间段内处理多个不同优先级的更新任务,并能根据优先级决定执行顺序和中断低优先级任务的能力。
与Fiber的关系:Fiber提供了可中断的机制,并发模式定义了如何利用这些机制提升体验(提供了API)。
React 并发模式(Concurrent Mode) 是一种渲染机制,允许 React中断、暂停或优先处理任务,提升应用响应速度。它通过时间切片(Time Slicing) 和优先级调度避免主线程阻塞,支持流畅交互(如输入时保持UI响应)。
核心API包括:startTransition(标记非紧急更新)、useTransition(控制加载状态)、Suspense(异步加载降级)。适用于复杂UI和高频更新场景。
Suspense:
// 如果遇到 Suspense(抛出 Promise):
// 1. 暂停当前渲染
// 2. 显示 fallback
// 3. Promise 解决后,恢复渲染
// 4. 无缝切换到实际内容
六、事件系统-合成事件
6.1 原理
React合成事件是通过顶层事件委托加标准化封装实现的跨浏览器事件系统,核心解决兼容性问题,优化性能,并为React高级特性提供底层支持。React 17版本以后,事件委托从document改为root。
Vue 直接使用原生 DOM 事件对象(但做了兼容性处理),通过修饰符简化了常见操作,无需手动处理事件对象的细节。
6.2 和原生事件的触发顺序
React 合成事件与原生事件的执行顺序遵循 『原生先于合成』 原则:
i. 原生事件从目标元素向上冒泡(自下而上)
ii.到达 React 根容器后触发合成事件
iii.合成事件在组件树中先捕获后冒泡(自上而下再自下而上)
6.3 如何阻止事件冒泡
e.stopPropagation() 在合成事件中只阻断 React 事件传播
原生事件中的 e.stopImmediatePropagation() 会阻断所有事件
七、React高级特性
7.1 Portal
允许你将组件的渲染内容挂载到 DOM 树中的任意一个位置,而不是当前组件的 DOM 层级中。这在处理模态框、弹窗、提示框等场景时非常有用,可以避免 CSS 样式冲突(如 z-index 问题)和父元素样式限制(如 overflow: hidden)。
注意:
-
DOM 结构分离:内容虽然在 JSX 中与父组件一起编写,但实际会被渲染到指定的 DOM 节点中
-
事件冒泡:尽管 DOM 结构分离,Portal 内部的事件仍然会按照 React 组件树的层级冒泡,而不是 DOM 树层级
-
上下文共享:Portal 可以访问父组件提供的 React 上下文(Context)
使用:
ReactDOM.createPortal()