一、基础原理类:
React 的核心特性有哪些?
- 组件化:将 UI 拆分为独立可复用的组件
- 声明式编程:关注 "是什么" 而非 "怎么做"
- 虚拟 DOM:减少真实 DOM 操作提升性能
- 单向数据流:数据流动可预测,便于调试
- JSX 语法:JavaScript 与 HTML 结合的语法糖
- 生命周期管理:组件不同阶段的钩子函数
- 状态管理:组件内部状态与外部状态管理
什么是 JSX?它的本质是什么?
- JSX 是 JavaScript XML 的缩写,是 React 中用于描述 UI 的语法扩展。本质上,JSX 是
React.createElement()
函数的语法糖,会被 Babel 等工具编译为 JavaScript 对象,最终被 React 渲染为真实 DOM。
React 中的虚拟 DOM 是什么?它是如何提高性能的?
虚拟 DOM 是内存中的 JavaScript 对象,是对真实 DOM 的轻量级抽象。它通过以下方式提高性能:
- 减少直接操作 DOM 的次数(DOM 操作代价高)
- 通过 diff 算法计算最小变更集
- 批量处理 DOM 更新,减少重排重绘
React 事件处理与原生 DOM 事件有什么区别?
- React 事件是合成事件(SyntheticEvent),模拟原生事件但有跨浏览器一致性
- React 事件绑定在 document 上而非元素本身,采用事件委托机制
- 事件处理函数中的 this 默认是 undefined,需手动绑定
- 事件命名采用驼峰式(如 onClick)而非小写(如 onclick)
props 和 state 的区别是什么?
- props 是从父组件传递到子组件的数据,只读不可修改
- state 是组件内部管理的数据,可以修改且修改会触发重渲染
- props 用于组件间通信,state 用于组件内部状态管理
- props 的变化会触发子组件重新渲染,state 的变化会触发当前组件重新渲染
二、Hooks 相关
说说你对 React Hook 的闭包陷阱的理解,有哪些解决方案?
闭包陷阱指 Hooks 中,回调函数捕获的是定义时的状态值,而非最新值。
解决方案:
- 使用 ref 存储最新值
- 将依赖项正确添加到依赖数组
- 使用函数式更新(setState (prev => prev + 1))
- 拆分 useEffect 为多个,减少依赖
如何让 useEffect 支持 async/await?
不能直接将 useEffect 的回调设为 async 函数,因为会返回 Promise 而非清理函数。
正确做法:
useEffect(() => {
const fetchData = async () => {
const result = await api.getData();
setData(result);
};
fetchData();
}, []);
useState 是如何实现的?
useState 基于 React 的内部状态管理机制,大致原理:
- 每个组件有一个对应的 fiber 节点存储状态
- 调用 useState 会返回当前状态和更新函数
- 更新函数会标记组件为脏组件,触发重新渲染
- 重新渲染时从 fiber 中读取最新状态
useMemo 和 useCallback 有什么区别?
- 两者都是用于性能优化,避免不必要的计算和渲染
- useMemo 缓存计算结果(值),接收一个函数和依赖数组
- useCallback 缓存函数本身,返回记忆化的函数
- useMemo 用于避免昂贵的计算,useCallback 用于避免子组件不必要的重渲染
三、Fiber 架构类
React Fiber 是什么?它是如何实现更新过程可控的?
Fiber 是 React 16 引入的新协调引擎,本质是重新实现的堆栈,目的是实现增量渲染。
它通过将渲染工作分解为小单元,每个单元完成后检查是否有更高优先级任务,实现了更新过程的可控性,可以暂停、恢复甚至终止任务。
fiber 是如何实现时间切片的?
Fiber 利用 requestIdleCallback API 或 setTimeout 模拟浏览器空闲时间,在每个时间片(通常是 16ms)内处理一部分工作,当时间片用完或有更高优先级任务时,暂停当前工作并保存状态,待下一次空闲时恢复工作。
Fiber 为什么是 React 性能的一个飞跃?
- 实现了增量渲染,避免长时间占用主线程
- 优先级调度机制,确保高优先级任务(如用户输入)优先执行
- 可中断和恢复的渲染过程,提升用户体验
- 更好地支持复杂 UI 和动画效果
React Reconciler 为何要采用 fiber 架构?
旧的 Stack Reconciler 采用递归方式,一旦开始无法中断,对于复杂组件可能导致主线程阻塞,造成页面卡顿。Fiber 架构解决了这个问题,使 Reconciliation 过程变得可中断、可恢复,并有优先级之分,大幅提升了 React 在复杂应用中的性能表现。
四、性能优化类
React 有哪些性能优化的方法?
- 使用 React.memo、useMemo、useCallback 减少不必要的重渲染
- 合理设置 key 属性,优化 diff 算法效率
- 代码分割(React.lazy 和 Suspense)
- 虚拟列表处理大量数据渲染
- 避免在渲染过程中创建函数和对象
- 使用 windowing 技术(如 react-window)处理长列表
- 优化 state 设计,避免冗余状态
- 使用 web workers 处理复杂计算
React.memo 和 PureComponent 的区别是什么?
- 两者都用于避免不必要的重渲染
- React.memo 用于函数组件,PureComponent 用于类组件
- React.memo 接受一个比较函数作为第二个参数,可自定义比较逻辑
- PureComponent 通过浅层比较 props 和 state 决定是否重渲染
key 属性在 diff 算法中的作用是什么?
key 是列表中元素的唯一标识,帮助 React 识别哪些元素发生了变化、被添加或移除。正确的 key 值可以使 diff 算法更高效,避免不必要的元素重新创建,提高性能。不建议使用索引作为 key,可能导致状态错乱。
如何避免不必要的组件渲染?
- 使用 React.memo 包装组件
- 类组件中使用 shouldComponentUpdate 生命周期
- 使用 useMemo 缓存计算结果
- 使用 useCallback 缓存回调函数
- 拆分组件,将频繁变化的部分与稳定部分分离
- 合理设计状态,避免状态提升过高
五、组件通信与状态管理类
React 组件间怎么进行通信?
- 父子组件:props 传递数据,回调函数传递事件
- 子父组件:回调函数、自定义事件
- 跨级组件:Context API、状态管理库
- 兄弟组件:共同父组件中转、状态管理库
- 任意组件:全局状态管理(Redux、MobX 等)、事件总线
说说对受控组件和非受控组件的理解,以及应用场景?
- 受控组件:表单数据由 React 状态控制,通过 onChange 更新状态
- 应用场景:需要实时验证、表单联动、需要立即处理用户输入的场景
- 非受控组件:表单数据由 DOM 本身管理,通过 ref 获取值
- 应用场景:简单表单、文件上传、集成非 React 表单库
Redux 的工作原理是什么?常用的中间件有哪些?
Redux 基于三大原则:单一数据源、状态只读、使用纯函数修改。
工作流程:
- 组件通过 dispatch 触发 action
- reducer 根据 action 类型更新 state
- store 通知组件 state 变化,组件重新渲染
常用中间件:
- redux-thunk:处理异步 action
- redux-saga:更强大的异步处理,支持取消等操作
- redux-observable:基于 RxJS 处理异步
- redux-logger:日志记录
React Router 的作用是什么?如何在使用 react-router 跳转时,将参数传递给下一个页面?
React Router 是 React 的路由管理库,用于实现单页应用的路由跳转和页面导航。
参数传递方式:
- URL 参数:
/user/:id
,通过 useParams () 获取 - 查询字符串:
/user?id=1
,通过 useSearchParams () 获取 - state 对象:
navigate('/user', { state: { id: 1 } })
,通过 useLocation () 获取 - 路由配置传递:在路由配置中定义参数
六、React 新特性类
React 19 有哪些新特性?
- 自动批处理(Automatic Batching):优化状态更新,减少渲染次数
- 服务器组件(Server Components)稳定版:允许组件在服务器渲染
- 过渡 API(useTransition)增强:更好地处理并发渲染
- 新的钩子:如 useDeferredValue、useId 等
- 改进的 Suspense:支持数据获取
- 废弃一些过时 API:如 ReactDOM.render
谈谈你对 React Server Components 的理解。
React Server Components(RSC)是在服务器端渲染的组件,不包含客户端状态和交互逻辑。
优势:
- 减少客户端 JavaScript 体积,提高加载速度
- 直接访问服务器资源,减少 API 调用
- 更好的 SEO 和首屏加载性能
- 与客户端组件无缝协作,共享代码
- 工作方式:服务器组件在服务器渲染为特殊格式,客户端接收并处理,保留交互能力。
React 中如何实现状态自动保存(KeepAlive)?
React 本身没有内置 KeepAlive 功能,但可通过以下方式实现:
- 使用 react-keep-alive 等第三方库
- 通过路由配置结合状态管理库(如 Redux)保存状态
- 使用 CSS 隐藏而非卸载组件(display: none)
- 利用缓存机制手动保存和恢复组件状态
- 在 React 18 + 中可结合 Suspense 和缓存策略实现类似效果