Skip to content

React 面试题

基础题

1. React 的核心思想是什么?基础

参考答案:

React 的核心思想可概括为四点:

  1. 组件化:把 UI 拆分为独立、可复用、可组合的组件,每个组件管理自己的状态和渲染。
  2. 声明式:开发者只需描述“UI 应该长什么样”,React 负责根据状态变化高效更新 DOM。
  3. 单向数据流:数据自顶向下通过 props 传递,子组件通过回调通知父组件修改状态,数据流向清晰可预测。
  4. 虚拟 DOM:用轻量 JS 对象描述真实 DOM,通过 Diff 算法最小化真实 DOM 操作,提升性能。

相比命令式 DOM 操作,声明式让代码更易理解、测试和复用。

评分维度

  • 能说出 3 个以上核心思想(40%)
  • 能结合实际说明(30%)
  • 能对比声明式与命令式(30%)

2. 什么是 JSX?基础

参考答案:

JSX 是 JavaScript 的语法扩展,允许在 JS 中编写类似 HTML 的结构。它既不是字符串,也不是模板引擎,而是会被编译为 React.createElement 调用。

示例:

const element = <h1 className="title">Hello</h1>;
// 编译后等价于
const element = React.createElement('h1', { className: 'title' }, 'Hello');

JSX 规则:

  • 必须有一个根节点(或用 Fragment <></>)。
  • 使用 className 而非 classhtmlFor 而非 for
  • 表达式用 {} 包裹,语句不行。
  • 标签名小写表示 HTML 元素,大写表示组件。

评分维度

  • 能解释 JSX 本质(30%)
  • 能说明编译结果(30%)
  • 能说出基本规则并给出示例(40%)

3. 类组件和函数组件有什么区别?基础

参考答案:

维度 类组件 函数组件
定义方式 ES6 class 普通函数
状态管理 this.state / this.setState useState / useReducer
生命周期 componentDidMount useEffect 组合模拟
代码量 较冗长 简洁
this 问题 需要绑定 this 无 this
官方推荐 legacy 场景 主流推荐

函数组件配合 Hooks 后能力完全覆盖类组件,且更利于逻辑复用和 Tree Shaking。类组件目前仅遗留项目或 Error Boundary 等少数场景使用。

评分维度

  • 能区分两种组件(40%)
  • 能说明生命周期和 Hooks 差异(30%)
  • 能说明函数组件优势(30%)

4. 什么是 React 的受控组件?基础

参考答案:

受控组件是指表单元素的值由 React 状态驱动,并通过 onChange 事件同步更新状态。

示例:

function Input() {
  const [value, setValue] = useState('');
  return (
    <input
      value={value}
      onChange={e => setValue(e.target.value)}
    />
  );
}

特点:

  • 输入值始终由 React 状态决定。
  • 便于做校验、格式化、联动控制。
  • 与非受控组件(通过 ref 读取 DOM 值)相比,受控组件更符合 React 数据驱动思想。

评分维度

  • 能解释受控组件(40%)
  • 能写出示例(30%)
  • 能对比非受控组件及适用场景(30%)

5. React 中的 key 有什么作用?基础

参考答案:

key 是 React Diff 算法中用于标识列表元素的特殊属性,帮助 React 判断元素是新增、删除、移动还是复用。

最佳实践:

  • 使用稳定且唯一的标识(如数据库 ID)作为 key。
  • 避免使用数组索引作为 key,除非列表纯展示且不会增删排序;否则会导致状态错位、性能下降。

示例:

{list.map(item => (
  <li key={item.id}>{item.name}</li>
))}

key 只在兄弟节点间比较,不参与组件 props 传递,因此不能通过 props.key 读取。

评分维度

  • 能解释 key 作用(40%)
  • 能说明为什么不能用索引作为 key(30%)
  • 能给出正确使用方式(30%)

进阶题

6. 解释 React 的 Fiber 架构。进阶

参考答案:

Fiber 是 React 16 引入的协调(Reconciliation)引擎重写,目标是把渲染工作拆分为可中断、可优先级调度的小单元。

核心能力:

  1. 增量渲染:把更新拆成多个小任务,避免长时间阻塞主线程。
  2. 任务暂停与恢复:浏览器空闲时继续执行,高优先级任务可插队。
  3. 错误边界:通过 Fiber 树定位错误范围。
  4. 双缓冲:维护 current 树(当前屏幕)和 workInProgress 树(正在计算),渲染完成后一次性切换。

Fiber 节点包含类型、props、state、effect、child、sibling、return 等指针,构成链表树,支持遍历和中断。

评分维度

  • 能解释 Fiber 解决的问题(30%)
  • 能说明任务可中断与优先级调度(40%)
  • 能提到双缓冲与错误边界(30%)

7. useEffect 的依赖数组有什么作用?进阶

参考答案:

useEffect 的第二个参数是依赖数组,控制 effect 执行时机:

  • 不传:每次渲染后都执行。
  • 空数组 []:只在组件挂载和卸载时执行,常用于初始化或订阅。
  • 有依赖:依赖变化时执行,变化通过 Object.is 比较。

依赖数组必须包含 effect 中使用的所有响应式值(state、props、函数等),否则会产生“闭包陷阱”,读到过期的状态。

示例:

useEffect(() => {
  console.log(count);
}, [count]);

// 订阅与清理
useEffect(() => {
  const handler = () => setCount(c => c + 1);
  window.addEventListener('click', handler);
  return () => window.removeEventListener('click', handler);
}, []);

如果 effect 里用到了某个值但遗漏在依赖中,ESLint react-hooks/exhaustive-deps 会警告。对于函数依赖,可用 useCallback 稳定引用或把函数定义在 effect 内部。

评分维度

  • 能说明三种情况(35%)
  • 能强调依赖完整性(25%)
  • 能举例说明闭包问题和清理函数(25%)
  • 知道如何处理函数依赖(15%)

8. React.memo、useMemo、useCallback 有什么区别?进阶

参考答案:

三者都用于性能优化,但作用层次不同:

  • React.memo:高阶组件,缓存函数组件。props 浅比较不变时跳过重渲染。
  • useMemo:缓存计算结果。依赖不变时返回上次计算值。
  • useCallback:缓存函数引用。依赖不变时返回同一函数实例,常用于避免子组件 props 引用变化导致重渲染。

示例:

const memoizedValue = useMemo(() => compute(a, b), [a, b]);
const memoizedFn = useCallback(() => doSomething(a), [a]);

// 配合 React.memo 使用
const Child = React.memo(({ onClick }) => <button onClick={onClick}>Click</button>);

注意:不要滥用,它们本身也有开销。优先定位真实性能瓶颈(如大列表、复杂渲染、频繁重渲染的子组件),再用 React DevTools Profiler 验证。同时注意依赖数组的完整性,否则 memo 会失效。

评分维度

  • 能区分三者作用(35%)
  • 能说明使用场景(30%)
  • 能提醒不要滥用并提到 Profiler(20%)
  • 能说明依赖完整性对 memo 的影响(15%)

9. 什么是 React Context?进阶

参考答案:

Context 提供了一种跨组件层级传递数据的方式,避免 props 层层透传(props drilling)。

基本用法:

const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div>{theme}</div>;
}

注意事项:

  • Context 适合低频变化的全局数据,如主题、语言、用户信息。
  • 不适合高频更新场景,因为 Provider value 变化会导致所有消费组件重渲染。
  • 可结合 useMemo 拆分 Context,减少不必要更新。

评分维度

  • 能解释 Context 作用(30%)
  • 能写出基本用法(40%)
  • 能说明性能注意事项(30%)

10. React Router v6 相比 v5 有哪些变化?进阶

参考答案:

主要变化:

  1. <Routes> 替代 <Switch>:Routes 支持相对路由和嵌套路由声明。
  2. element 替代 component:直接写 JSX,更灵活。
  3. useNavigate 替代 useHistory
    const navigate = useNavigate();
    navigate('/home');
    
  4. 嵌套路由声明化:子路由在父路由中直接声明,配合 <Outlet /> 渲染。
  5. Hook API 调整:移除 useParams 之外的部分旧 API,新增 useLocationuseMatch 等。
  6. 路由配置对象:支持 useRoutes 进行配置化路由。

v6 整体更强调声明式、嵌套和相对路径,适合构建复杂路由结构。

评分维度

  • 能说出 3 个以上变化(40%)
  • 能说明 API 变化(30%)
  • 能说明嵌套路由改进(30%)

高级题

11. 解释 React 的 Concurrent Mode。深入

参考答案:

Concurrent Mode(并发特性,React 18 正式引入)允许 React 同时准备多个版本的 UI,并根据任务优先级决定何时提交到屏幕。

核心 API:

  • useTransition:把非紧急更新标记为 transition,避免阻塞用户输入。
    const [isPending, startTransition] = useTransition();
    startTransition(() => setQuery(value));
    
  • useDeferredValue:延迟更新某个值,让紧急更新先渲染。
  • Suspense:声明式处理异步边界,支持数据获取和流式 SSR。

解决的问题:

  • 大量数据更新时界面卡顿。
  • 用户输入被渲染阻塞。
  • 更好的加载状态控制。

评分维度

  • 能解释并发概念(30%)
  • 能说出主要 API(40%)
  • 能说明解决的问题(30%)

12. React 18 有哪些新特性?深入

参考答案:

React 18 主要特性:

  1. 自动批处理(Automatic Batching):在 setTimeout、Promise 等异步回调中也能自动合并多次状态更新,减少重渲染。
  2. Concurrent Rendering:可中断渲染,提升交互响应。
  3. 新的 Root API
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<App />);
    
  4. useTransition / useDeferredValue:区分紧急与非紧急更新。
  5. Suspense 改进:支持数据获取、流式 SSR(Streaming SSR)。
  6. useId:生成稳定唯一 ID,适用于表单 label 与 SSR hydration。
  7. Strict Mode 行为调整:开发环境下会故意双重调用某些函数,帮助发现副作用。

评分维度

  • 能说出 4 个以上特性(40%)
  • 能解释 createRoot(30%)
  • 能说明自动批处理(30%)

13. 如何选择 React 状态管理方案?深入

参考答案:

选择应基于应用规模和状态特征:

场景 推荐方案
组件局部状态 useState / useReducer
跨组件低频状态 Context + useState/useReducer
中小型应用 Zustand、Jotai、Recoil
大型应用、复杂流程 Redux、MobX、Redux Toolkit
服务端状态 React Query / SWR / RTK Query

选择依据:

  • 状态复杂度与更新频率。
  • 是否需要中间件、时间旅行调试。
  • 团队熟悉度和生态成熟度。
  • 是否需要服务端缓存与自动同步。

避免把所有状态都放全局,优先使用局部状态,减少不必要的耦合。

评分维度

  • 能说出 3 种以上方案(30%)
  • 能说明选择依据(40%)
  • 能避免过度使用全局状态(30%)

14. 什么是 React Server Components?深入

参考答案:

React Server Components(RSC)是在服务端渲染的组件,不会打包到客户端。它们可以直接访问数据库、文件系统等服务端资源,只把渲染结果发送到客户端。

与 SSR 的区别:

  • SSR:生成完整 HTML,客户端仍需下载组件 JS 并 hydrate。
  • RSC:不生成 HTML,而是返回特殊序列化数据;组件代码不进入 bundle,减少客户端 JS 体积。

特点:

  • 可访问服务端资源。
  • 与客户端组件可组合使用。
  • 天然适合数据密集型页面。

Next.js App Router 是当前 RSC 的主要实践载体。

评分维度

  • 能解释 Server Components(40%)
  • 能说明与 SSR 区别(30%)
  • 能说明优势与典型场景(30%)

15. 如何优化 React 应用性能?深入

参考答案:

React 性能优化应遵循“先测量,后优化”:

  1. 避免不必要渲染React.memouseMemouseCallback
  2. 拆分任务useTransitionuseDeferredValue 把非紧急更新推迟。
  3. 代码分割React.lazy + Suspense,按路由/组件懒加载。
  4. 长列表优化:虚拟列表(react-window、react-virtualized)。
  5. Context 优化:拆分 Context、使用 useMemo 缓存 value。
  6. 状态管理优化:避免全局状态滥用,服务端状态用 React Query/SWR。
  7. 图片与资源优化:懒加载、WebP、响应式图片。
  8. 使用 Profiler:定位真实瓶颈。

避免过早优化,先通过 React DevTools Profiler 确认问题所在。

评分维度

  • 能说出 4 种以上方法(40%)
  • 能解释原理(30%)
  • 能提醒不要过早优化并提到 Profiler(30%)

补充题

16. 什么是错误边界?基础

参考答案:

错误边界(Error Boundary)是 React 组件,用于捕获子组件树中的 JavaScript 错误,防止整个应用崩溃,并展示兜底 UI。

特点:

  • 只能捕获渲染期、生命周期和构造函数中的错误。
  • 无法捕获事件处理函数、异步代码、SSR、自身错误的错误。
  • 必须使用类组件实现,通过 static getDerivedStateFromErrorcomponentDidCatch

示例:

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError() {
    return { hasError: true };
  }
  render() {
    return this.state.hasError ? <h1>出错了</h1> : this.props.children;
  }
}

评分维度

  • 能解释概念(40%)
  • 能说明限制(30%)
  • 能写出基本示例(30%)

17. React 中如何获取 DOM 节点?基础

参考答案:

使用 useRef(函数组件)或 createRef(类组件)获取 DOM 节点。

示例:

function Input() {
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current.focus();
  }, []);
  return <input ref={inputRef} />;
}

ref 也可以指向组件实例(类组件)或自定义值。注意 ref 不会触发组件重渲染,修改 ref.current 是副作用,应在事件处理或 useEffect 中操作。

评分维度

  • 能说出 useRef/createRef(40%)
  • 能写出示例(30%)
  • 能说明 ref 的特性与注意事项(30%)

18. 什么是 Portal?基础

参考答案:

Portal 允许把子节点渲染到父组件 DOM 树以外的节点,常用于模态框、提示框、抽屉等需要脱离当前布局上下文的场景。

示例:

import { createPortal } from 'react-dom';

function Modal({ children }) {
  return createPortal(
    <div className="modal">{children}</div>,
    document.getElementById('modal-root')
  );
}

Portal 中的子组件事件仍会冒泡到 React 组件树中的父组件,因此事件行为与普通子组件一致。

评分维度

  • 能解释概念(40%)
  • 能说明使用场景(30%)
  • 能写出基本示例(30%)

19. React 中的 SyntheticEvent 是什么?基础

参考答案:

SyntheticEvent 是 React 对浏览器原生事件的跨浏览器包装对象,提供一致的 API(如 stopPropagationpreventDefault)。

特点:

  • 抹平浏览器差异,开发者无需判断 IE/Chrome 的不同 API。
  • 采用事件委托:React 17 之前委托到 document,React 17 之后委托到 Root 容器。
  • SyntheticEvent 会被复用(事件池,React 17 之前),因此异步访问事件属性需先 e.persist();React 17 之后已取消事件池。

示例:

function Button() {
  const handleClick = (e) => {
    e.preventDefault();
    console.log(e.target);
  };
  return <button onClick={handleClick}>Click</button>;
}

评分维度

  • 能解释合成事件(40%)
  • 能说明跨浏览器一致性和事件委托(30%)
  • 能提到事件池变化(30%)

20. 你如何看待 React 的未来发展?基础

参考答案:

React 的未来发展方向:

  1. Server Components 普及:减少客户端 JS,提升数据密集型页面性能。
  2. 并发特性成为默认:useTransition、useDeferredValue、Suspense 会越来越常用。
  3. 与框架深度集成:Next.js、Remix 等全栈框架成为 React 应用的主流载体。
  4. 边缘渲染与流式 SSR:借助 Edge Function、Streaming 提升首屏与交互体验。
  5. AI 辅助开发:结合 AI 工具提升组件生成、测试、文档效率。

作为开发者,应持续关注 React 核心原理(Fiber、Hooks、并发),同时根据业务场景选择合适的技术栈,避免盲目追新。

评分维度

  • 能说出 3 个以上趋势(40%)
  • 能分析原因(30%)
  • 能表达理性学习态度(30%)

21. React 19 有哪些重要新特性?基础

参考答案:

React 19 主要新特性:

  1. Actions:把异步数据变更函数标记为 action,自动处理 pending 状态。
  2. useOptimistic:乐观更新,异步操作完成前先更新 UI。
  3. use Hook:在渲染中读取 Promise / Context,配合 Suspense 使用。
  4. React Compiler:编译时自动记忆化,减少手动 useMemo/useCallback/React.memo
  5. Server Actions:客户端直接调用服务端函数。
  6. 改进的表单处理:原生表单与 React 状态更深度集成。

示例:

function Messages({ messages }) {
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, text) => [...state, { text, sending: true }]
  );

  async function sendMessage(formData) {
    const text = formData.get("message");
    addOptimisticMessage(text);
    await deliverMessage(text);
  }

  return (
    <form action={sendMessage}>
      {optimisticMessages.map((msg, i) => (
        <div key={i} style=&#123;&#123; opacity: msg.sending ? 0.5 : 1 &#125;&#125;>{msg.text}</div>
      ))}
      <input name="message" />
      <button>发送</button>
    </form>
  );
}

评分维度

  • 能说出 4 个以上新特性(40%)。
  • 能解释 Actions / useOptimistic / use 至少一个(30%)。
  • 能说明 React Compiler 的意义(30%)。

22. 什么是 Server Actions?它解决了什么问题?基础

参考答案:

Server Actions 允许在服务端定义函数,客户端像调用普通函数一样调用它们,无需手写 REST/GraphQL API。

示例:

// actions.js
"use server";
export async function updateName(formData) {
  await db.user.update({ where: { id: 1 }, data: { name: formData.get("name") } });
}

// page.jsx
import { updateName } from "./actions";
export default function Page() {
  return <form action={updateName}><input name="name" /><button>更新</button></form>;
}

优势:

  • 减少样板代码。
  • 类型安全。
  • 可直接访问数据库和内部服务。
  • 渐进增强,JS 禁用时原生表单仍可工作。

安全:必须验证输入、校验权限、防止 CSRF。

评分维度

  • 能解释 Server Actions 概念(30%)。
  • 能写出基本示例(30%)。
  • 能说明优势和注意事项(40%)。

23. 什么是 Hydration 失败?常见原因和解决方案有哪些?基础

参考答案:

Hydration 是 SSR/SSG 应用把服务端生成的 HTML 激活为可交互组件的过程。如果服务端和客户端首次渲染结果不一致,React 会报 hydration 错误。

常见原因:

  • new Date()Math.random()crypto.randomUUID() 在两端结果不同。
  • 客户端从 localStorage 读取主题/语言。
  • 浏览器 API(windowdocument)在服务端不存在。
  • 第三方脚本修改了 React 管理的 DOM。

解决方案:

  • 把客户端逻辑放到 useEffectClientOnly 组件中。
  • 统一数据源,时间/随机数从服务端传入或固定。
  • 对无法避免的不一致加 suppressHydrationWarning
  • 监控 hydration 错误并接入错误上报。

评分维度

  • 能解释 hydration 概念(30%)。
  • 能说出 3 个以上常见原因(30%)。
  • 能给出 3 个以上解决方案(40%)。

领域编号:E06 React
最后更新:2026-06-24

基于 MIT 协议发布