React 面试题

#前端#React#框架

前端面试题 - React篇

本文档系统整理了React面试的高频题目,涵盖React核心概念、Hooks详解、React 18/19新特性、状态管理、性能优化、路由、服务端渲染、测试、源码原理等核心知识点。


文档概览

React在前端面试中的重要性

React作为目前最流行的前端框架之一,在各大公司的前端面试中占据重要地位。掌握React不仅是面试的必备技能,也是现代前端开发的核心能力。本文档整理的题目来源于2024-2025年真实面试场景,具有极高的参考价值。

题目统计

分类题目数量难度分布
React核心概念15题基础10题 / 中级3题 / 高级2题
Hooks详解20题基础6题 / 中级10题 / 高级4题
React 18/19新特性18题基础4题 / 中级11题 / 高级3题
状态管理15题基础3题 / 中级11题 / 高级1题
性能优化15题基础2题 / 中级9题 / 高级4题
React Router v612题基础5题 / 中级6题 / 高级1题
服务端渲染(Next.js)15题基础2题 / 中级9题 / 高级4题
测试10题基础4题 / 中级6题
源码原理15题高级15题
高级特性与其他10题基础2题 / 中级5题 / 高级3题
总计145题基础38题 / 中级70题 / 高级37题

React版本覆盖说明

本文档涵盖React 16.8+至React 19的最新特性:

  • React 16.8: Hooks首次引入
  • React 17: 事件委托机制变更、JSX转换优化
  • React 18: 并发渲染、自动批处理、新Hooks(useId/useTransition/useDeferredValue等)
  • React 19: Actions、新Hooks(useOptimistic/useActionState)、React Compiler

目录


一、React核心概念

基础概念

1. 什么是React?它的核心特性有哪些?

难度:⭐(基础) 标签:#React基础 #核心概念

问题描述: 请介绍React是什么,以及它相比其他前端框架的核心优势。

参考答案要点

  • React是用于构建用户界面的JavaScript库,由Facebook开发和维护
  • 核心特性
    • 虚拟DOM:通过JavaScript对象模拟真实DOM,减少直接操作DOM的性能开销
    • 组件化:将UI拆分为独立、可复用的组件,提高代码可维护性
    • 单向数据流:数据从父组件流向子组件,便于追踪数据变化
    • 声明式编程:描述UI应该是什么样子,而非如何操作DOM
    • JSX语法:在JavaScript中编写类似HTML的代码,提高开发效率

2. 什么是JSX?它与普通JavaScript有什么区别?

难度:⭐(基础) 标签:#JSX #语法

问题描述: 解释JSX的概念,以及它在React中的作用和编译过程。

参考答案要点

  • JSX是JavaScript的语法扩展,允许在JS中编写类似HTML的代码
  • 编译过程:JSX会被Babel等工具编译为React.createElement()调用
  • 重要规则
    • 组件名必须大写开头,否则会被认为是原生DOM标签
    • 必须有一个根元素包裹
    • 使用{}嵌入JavaScript表达式
    • class要写成classNamefor要写成htmlFor

代码示例

JavaScript JSX
// JSX写法
const element = <h1 className="title">Hello, React!</h1>

// 编译后
const element = React.createElement(
  "h1",
  { className: "title" },
  "Hello, React!"
)

3. 什么是虚拟DOM?它的工作原理是什么?

难度:⭐(基础) 标签:#虚拟DOM #Diff算法

问题描述: 请解释虚拟DOM的概念、工作原理以及它带来的优势。

参考答案要点

  • 虚拟DOM是真实DOM的JavaScript对象表示,是轻量级的副本
  • 工作原理
    1. 数据变化时创建新的虚拟DOM树
    2. 通过Diff算法比较新旧虚拟DOM的差异
    3. 只更新变化的部分到真实DOM(Patch操作)
  • 优势
    • 减少DOM操作次数,提高性能
    • 跨平台能力(React Native)
    • 声明式编程,开发者无需手动操作DOM

4. 类组件和函数组件有什么区别?

难度:⭐(基础) 标签:#组件 #类组件 #函数组件

问题描述: 比较React中的类组件和函数组件,说明各自的优缺点。

参考答案要点

特性类组件函数组件
定义方式ES6 Class普通函数
状态管理this.stateuseState Hook
生命周期有完整生命周期方法useEffect模拟
this指向需要处理this绑定无this,更简洁
代码量相对较多更简洁
测试难度较难更容易测试
逻辑复用HOC/Render Props自定义Hooks

推荐:新项目优先使用函数组件 + Hooks


5. 什么是Props和State?它们有什么区别?

难度:⭐(基础) 标签:#Props #State #数据流

问题描述: 解释Props和State的概念,以及它们在React组件中的作用和区别。

参考答案要点

特性PropsState
数据来源父组件传递组件内部管理
可变性只读(Read-only)可变(通过setState)
用途组件间通信组件内部状态管理
更新影响触发子组件重新渲染触发组件重新渲染
默认值可设置defaultProps可在构造函数/useState中设置

核心原则:Props向下传递,State内部管理


6. 什么是受控组件和非受控组件?

难度:⭐(基础) 标签:#表单 #受控组件 #非受控组件

问题描述: 解释受控组件和非受控组件的概念,以及各自的使用场景。

参考答案要点

  • 受控组件:表单数据由React组件的state管理,通过onChange事件更新
    • 优点:便于验证、测试、与其他UI状态同步
    • 缺点:代码量稍多
  • 非受控组件:表单数据由DOM自身管理,通过ref获取值
    • 优点:代码简洁,类似传统HTML表单
    • 缺点:难以进行实时验证和状态同步

代码示例

JavaScript JSX
// 受控组件
function ControlledInput() {
  const [value, setValue] = useState("")
  return <input value={value} onChange={(e) => setValue(e.target.value)} />
}

// 非受控组件
function UncontrolledInput() {
  const inputRef = useRef(null)
  const handleSubmit = () => {
    console.log(inputRef.current.value)
  }
  return <input ref={inputRef} />
}

7. React组件间通信的方式有哪些?

难度:⭐(基础) 标签:#组件通信 #Props #Context

问题描述: 列举React中组件间通信的各种方式,并说明各自的适用场景。

参考答案要点

  1. 父子组件通信:Props传递(父→子)、回调函数(子→父)
  2. 兄弟组件通信:状态提升到共同父组件
  3. 跨层级通信:Context API
  4. 全局状态管理:Redux、Zustand、Jotai等
  5. 发布订阅模式:Event Bus
  6. URL参数:路由传参

8. React中key的作用是什么?

难度:⭐(基础) 标签:#Key #列表渲染 #Diff算法

问题描述: 解释React中key属性的作用,以及为什么不应该使用数组索引作为key。

参考答案要点

  • 作用
    • 帮助React识别哪些元素改变了、被添加或被删除
    • 在Diff算法中用于判断元素是否可以复用
    • 提高列表渲染性能
  • 为什么不建议用索引作为key
    • 列表项顺序变化时会导致不必要的重新渲染
    • 可能产生状态错乱问题
    • 删除/插入元素时性能差
  • 最佳实践:使用唯一稳定的ID作为key

组件与生命周期

9. React生命周期方法有哪些?

难度:⭐⭐(中级) 标签:#生命周期 #类组件

问题描述: 详细介绍React类组件的生命周期方法及其执行时机。

参考答案要点

挂载阶段

  • constructor:初始化state和绑定方法
  • static getDerivedStateFromProps:根据props更新state
  • render:渲染UI(必须实现)
  • componentDidMount:组件挂载后,适合发起网络请求、订阅

更新阶段

  • static getDerivedStateFromProps
  • shouldComponentUpdate:控制是否重新渲染,用于性能优化
  • render
  • getSnapshotBeforeUpdate:获取更新前DOM快照
  • componentDidUpdate:组件更新后

卸载阶段

  • componentWillUnmount:清理工作(定时器、订阅、事件监听等)

错误处理

  • static getDerivedStateFromError:渲染备用UI
  • componentDidCatch:记录错误信息

10. setState是同步还是异步的?

难度:⭐⭐(中级) 标签:#setState #异步更新 #批处理

问题描述: 解释setState的同步/异步行为,以及React 18的自动批处理特性。

参考答案要点

  • React 17及之前
    • React事件处理函数中:异步执行,批量更新
    • setTimeout/Promise中:同步执行
  • React 18
    • 自动批处理(Automatic Batching):所有更新都批量处理
    • 包括Promise、setTimeout、原生事件中的更新
  • 强制同步更新:使用flushSync

代码示例

JavaScript JSX
import { flushSync } from "react-dom"

// React 18自动批处理
setTimeout(() => {
  setCount((c) => c + 1) // 不会立即更新
  setFlag((f) => !f) // 合并为一次更新
}, 1000)

// 强制同步
flushSync(() => {
  setCount((c) => c + 1) // 立即更新
})

11. 什么是React的错误边界(Error Boundary)?

难度:⭐⭐(中级) 标签:#错误边界 #异常处理

问题描述: 解释错误边界的概念、实现方式以及局限性。

参考答案要点

  • 实现方式:使用static getDerivedStateFromErrorcomponentDidCatch
  • 作用:捕获子组件树的JavaScript错误,显示降级UI
  • 能捕获的错误
    • 渲染期错误
    • 生命周期方法中的错误
    • 构造函数中的错误
  • 不能捕获的错误
    • 事件处理函数中的错误
    • 异步代码中的错误
    • 服务端渲染的错误
    • 错误边界自身抛出的错误

代码示例

JavaScript JSX
class ErrorBoundary extends React.Component {
  state = { hasError: false }

  static getDerivedStateFromError(error) {
    return { hasError: true }
  }

  componentDidCatch(error, errorInfo) {
    console.error("Error:", error, errorInfo)
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>
    }
    return this.props.children
  }
}

12. 什么是React Portal?

难度:⭐⭐(中级) 标签:#Portal #DOM操作

问题描述: 解释React Portal的概念和使用场景。

参考答案要点

  • Portal可以将子节点渲染到父组件以外的DOM节点
  • 使用ReactDOM.createPortal(child, container)
  • 事件冒泡:仍然按照React组件树进行,而非DOM树
  • 常见用途:模态框、提示框、下拉菜单等需要脱离父组件布局的场景

代码示例

JavaScript JSX
function Modal({ children, onClose }) {
  return ReactDOM.createPortal(
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </div>,
    document.getElementById("modal-root") // 渲染到body下的modal-root
  )
}

事件与Diff算法

13. 什么是React的合成事件系统?

难度:⭐⭐(中级) 标签:#合成事件 #事件委托

问题描述: 解释React合成事件系统的实现原理和特点。

参考答案要点

  • React使用SyntheticEvent封装原生事件,提供跨浏览器一致性
  • 事件委托机制:事件监听器挂载在root容器(React 17+),而非document
  • 事件池化(React 17前):合成事件对象会被复用,异步访问需要使用e.persist()
  • 执行顺序:原生事件先执行,合成事件后执行
  • 优势:减少内存占用、跨浏览器兼容、便于统一管理

14. 为什么React元素有$$typeof属性?

难度:⭐⭐⭐(高级) 标签:#安全 #XSS #React元素

问题描述: 解释React元素中$$typeof属性的作用和意义。

参考答案要点

  • 用于防止XSS攻击
  • $$typeof是一个Symbol类型(Symbol.for('react.element')
  • 安全机制
    • Symbol类型无法被JSON序列化
    • 阻止服务器JSON注入攻击
    • 确保元素是通过React.createElement创建的合法元素
  • 如果服务器返回的JSON中包含恶意{ type: 'script', props: { src: 'evil.js' } },由于缺少$$typeof,React会拒绝渲染

15. 什么是React的Diff算法?

难度:⭐⭐⭐(高级) 标签:#Diff算法 #虚拟DOM #Fiber

问题描述: 详细解释React Diff算法的实现原理和优化策略。

参考答案要点

  • 时间复杂度优化:从O(n³)优化到O(n)
  • 核心策略
    1. 同级比较:只比较同一层级的节点
    2. 类型不同则销毁重建:type不同直接替换整个子树
    3. 使用key优化列表:通过key识别元素身份
  • Diff过程
    1. 单节点Diff:比较type和key
    2. 多节点Diff:两轮遍历
      • 第一轮:复用相同位置的节点
      • 第二轮:处理移动、新增、删除

二、Hooks详解

基础Hooks

1. 什么是React Hooks?为什么要引入Hooks?

难度:⭐(基础) 标签:#Hooks #函数组件

问题描述: 介绍React Hooks的概念,以及它解决了类组件的哪些问题。

参考答案要点

  • Hooks是React 16.8引入的特性,让函数组件可以使用状态和生命周期
  • 解决的问题
    • 类组件的this指向问题
    • 逻辑复用困难(HOC嵌套地狱)
    • 生命周期方法逻辑分散
    • 大型类组件难以拆分和维护
  • 优势:代码更简洁、更易于测试和复用、逻辑聚合

2. useState的工作原理是什么?

难度:⭐(基础) 标签:#useState #状态管理

问题描述: 解释useState的工作原理和使用注意事项。

参考答案要点

  • 返回[state, setState]元组
  • 实现原理:基于闭包和链表实现状态存储
  • 重要规则
    • 每次渲染按顺序调用Hooks,不能放在条件语句中
    • 函数式更新:setState(prev => prev + 1),适用于依赖旧状态的场景
    • 初始值可以是函数,避免重复计算

代码示例

JavaScript JSX
function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount((c) => c + 1)}>函数式+1</button>
    </div>
  )
}

3. useEffect的依赖项数组有什么作用?

难度:⭐(基础) 标签:#useEffect #副作用 #依赖项

问题描述: 详细解释useEffect依赖项数组的不同写法及其效果。

参考答案要点

依赖项写法执行时机
不写依赖项每次渲染后都执行
空数组[]只在挂载时执行,卸载时清理
有依赖项[a, b]挂载时执行,依赖变化时执行
  • 返回的清理函数在卸载或重新执行前调用
  • 依赖项必须包含所有在effect中使用的响应式值

代码示例

JavaScript JSX
useEffect(() => {
  console.log("只在挂载时执行")
  return () => console.log("卸载时清理")
}, [])

useEffect(() => {
  console.log("count变化时执行:", count)
}, [count])

4. useRef的作用是什么?

难度:⭐(基础) 标签:#useRef #DOM引用

问题描述: 解释useRef的多种使用场景。

参考答案要点

  1. 获取DOM节点引用:操作原生DOM元素
  2. 保存可变值:存储不触发重新渲染的值
  3. 特性
    • 每次渲染返回同一ref对象
    • 修改ref.current不会导致重渲染
    • 适合存储定时器ID、上一轮的props/state等

代码示例

JavaScript JSX
function Timer() {
  const intervalRef = useRef(null)
  const inputRef = useRef(null)

  useEffect(() => {
    intervalRef.current = setInterval(() => {}, 1000)
    return () => clearInterval(intervalRef.current)
  }, [])

  const focusInput = () => {
    inputRef.current.focus()
  }

  return <input ref={inputRef} />
}

5. useContext如何使用?

难度:⭐(基础) 标签:#useContext #跨组件通信

问题描述: 介绍useContext的使用方法和注意事项。

参考答案要点

  • 接收Context对象,返回当前context值
  • 组件会在context值变化时重新渲染
  • 配合React.createContext和Provider使用
  • 可用于跨层级传递数据,避免prop drilling

代码示例

JavaScript JSX
const ThemeContext = React.createContext("light")

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

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

6. useId的作用是什么?

难度:⭐(基础) 标签:#useId #React18 #无障碍

问题描述: 介绍React 18新增的useId Hook的作用和使用场景。

参考答案要点

  • React 18新增Hook
  • 生成唯一的ID,用于无障碍性支持(如label和input的关联)
  • 服务端渲染支持:在服务端和客户端生成相同的ID,避免hydration不匹配
  • 返回的ID包含:字符,确保唯一性

代码示例

JavaScript JSX
function PasswordField() {
  const passwordId = useId()
  return (
    <>
      <label htmlFor={passwordId}>Password:</label>
      <input id={passwordId} type="password" />
    </>
  )
}

进阶Hooks

7. useEffect和useLayoutEffect有什么区别?

难度:⭐⭐(中级) 标签:#useEffect #useLayoutEffect #执行时机

问题描述: 比较useEffect和useLayoutEffect的执行时机和使用场景。

参考答案要点

特性useEffectuseLayoutEffect
执行时机异步,浏览器绘制后同步,DOM更新后、绘制前
阻塞渲染
SSR支持正常会警告(需用useEffect)
用途大多数副作用DOM测量和同步修改
  • useLayoutEffect可能阻塞视觉更新,谨慎使用
  • 用于测量DOM布局、防止视觉闪烁的场景

8. 什么是useMemo和useCallback?

难度:⭐⭐(中级) 标签:#useMemo #useCallback #性能优化

问题描述: 解释useMemo和useCallback的作用和使用场景。

参考答案要点

  • useMemo:缓存计算结果,依赖不变返回缓存值
  • useCallback:缓存函数引用,依赖不变返回同一函数
  • 用途:优化子组件渲染,避免不必要的重渲染
  • 注意事项:不要滥用,缓存本身也有开销

代码示例

JavaScript JSX
function Parent() {
  const [count, setCount] = useState(0)
  const [text, setText] = useState("")

  // 只有count变化时才重新计算
  const expensiveValue = useMemo(() => {
    return heavyComputation(count)
  }, [count])

  // 只有count变化时才创建新函数
  const handleClick = useCallback(() => {
    console.log(count)
  }, [count])

  return <Child onClick={handleClick} value={expensiveValue} />
}

9. 什么是forwardRef?

难度:⭐⭐(中级) 标签:#forwardRef #Ref转发

问题描述: 解释forwardRef的作用和使用场景。

参考答案要点

  • 用于将ref转发给子组件
  • 函数组件默认不能接受ref,需要使用forwardRef包裹
  • 高阶组件中需要使用forwardRef转发ref

代码示例

JavaScript JSX
const FancyInput = forwardRef((props, ref) => {
  return <input ref={ref} className="fancy-input" />
})

function Parent() {
  const inputRef = useRef(null)
  return <FancyInput ref={inputRef} />
}

10. useImperativeHandle的作用是什么?

难度:⭐⭐(中级) 标签:#useImperativeHandle #命令式API

问题描述: 解释useImperativeHandle的作用和使用场景。

参考答案要点

  • 自定义暴露给父组件的实例值
  • 配合forwardRef使用
  • 隐藏组件内部实现细节
  • 用于命令式操作子组件(如聚焦、播放等)

代码示例

JavaScript JSX
const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef(null)

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => {
      inputRef.current.value = ""
    },
  }))

  return <input ref={inputRef} />
})

11. useReducer适合什么场景?

难度:⭐⭐(中级) 标签:#useReducer #状态管理

问题描述: 介绍useReducer的适用场景和使用方法。

参考答案要点

  • 适用于复杂状态逻辑,多个子值相关
  • 下一个状态依赖于之前的状态
  • 需要复用状态逻辑
  • 类似Redux的工作方式

代码示例

JavaScript JSX
function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 }
    case "decrement":
      return { count: state.count - 1 }
    default:
      throw new Error()
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 })
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  )
}

12. useSyncExternalStore的作用是什么?

难度:⭐⭐(中级) 标签:#useSyncExternalStore #React18 #外部数据

问题描述: 介绍React 18新增的useSyncExternalStore Hook。

参考答案要点

  • React 18新增Hook
  • 用于订阅外部数据源(如浏览器API、第三方状态管理库)
  • 支持服务端渲染
  • 第三方状态管理库常用(如Zustand、Redux)

代码示例

JavaScript JSX
function useOnlineStatus() {
  return useSyncExternalStore(
    (callback) => {
      window.addEventListener("online", callback)
      window.addEventListener("offline", callback)
      return () => {
        window.removeEventListener("online", callback)
        window.removeEventListener("offline", callback)
      }
    },
    () => navigator.onLine, // 客户端获取
    () => true // 服务端默认值
  )
}

自定义Hooks

13. 什么是自定义Hook?

难度:⭐⭐(中级) 标签:#自定义Hook #逻辑复用

问题描述: 介绍自定义Hook的概念和编写规范。

参考答案要点

  • use开头的函数,可以调用其他Hooks
  • 用于复用状态逻辑,而非UI
  • 每次调用有独立的state和effect
  • 常见例子:useWindowSize、useFetch、useLocalStorage

代码示例

JavaScript JSX
function useWindowSize() {
  const [size, setSize] = useState({ width: 0, height: 0 })

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight })
    }
    window.addEventListener("resize", handleResize)
    handleResize()
    return () => window.removeEventListener("resize", handleResize)
  }, [])

  return size
}

14. 如何实现一个自定义的useDebounce Hook?

难度:⭐⭐(中级) 标签:#自定义Hook #防抖

问题描述: 实现一个防抖Hook,用于延迟更新值。

参考答案要点

  • 使用useState存储防抖后的值
  • 使用useEffect设置定时器
  • 清理函数清除之前的定时器

代码示例

JavaScript JSX
function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value)

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay)
    return () => clearTimeout(timer)
  }, [value, delay])

  return debouncedValue
}

// 使用
function SearchInput() {
  const [value, setValue] = useState("")
  const debouncedValue = useDebounce(value, 500)

  useEffect(() => {
    // 500ms后才执行搜索
    searchAPI(debouncedValue)
  }, [debouncedValue])

  return <input value={value} onChange={(e) => setValue(e.target.value)} />
}

15. 如何用Hooks模拟生命周期?

难度:⭐⭐(中级) 标签:#Hooks #生命周期

问题描述: 使用Hooks模拟类组件的各个生命周期方法。

参考答案要点

生命周期Hooks模拟方式
componentDidMountuseEffect(() => {}, [])
componentDidUpdateuseEffect(() => {}, [deps])
componentWillUnmountuseEffect(() => { return () => {} }, [])
getSnapshotBeforeUpdate无直接对应,可用useLayoutEffect近似

Hooks原理

16. Hooks的调用规则有哪些?

难度:⭐(基础) 标签:#Hooks规则 #ESLint

问题描述: 介绍Hooks的调用规则及其原因。

参考答案要点

  1. 只在最顶层调用Hooks:不要在循环、条件或嵌套函数中调用
  2. 只在React函数组件或自定义Hooks中调用
  3. ESLint插件eslint-plugin-react-hooks可强制执行规则

原因:React通过调用顺序维护Hooks状态链表,条件调用会导致顺序不一致


17. 为什么不能在条件语句中使用Hooks?

难度:⭐⭐⭐(高级) 标签:#Hooks原理 #链表

问题描述: 深入解释为什么Hooks不能在条件语句中使用。

参考答案要点

  • React通过数组/链表存储Hooks状态
  • 每个Hook对应一个节点,通过next指针连接
  • 渲染时按调用顺序访问链表
  • 条件调用会导致Hooks顺序错乱,造成状态混乱或报错

代码示例

JavaScript JSX
// ❌ 错误
if (condition) {
  useEffect(() => {}, [])
}

// ✅ 正确
useEffect(() => {
  if (condition) {
    // 逻辑放在effect内部
  }
}, [])

18. 什么是Hooks的闭包陷阱?如何解决?

难度:⭐⭐⭐(高级) 标签:#闭包陷阱 #依赖项

问题描述: 解释Hooks中的闭包陷阱问题及其解决方案。

参考答案要点

  • 问题:useEffect/useCallback中引用的state是旧值
  • 原因:闭包捕获了渲染时的state值
  • 解决方案
    1. 添加正确的依赖项
    2. 使用函数式更新setState(prev => ...)
    3. 使用useRef保存最新值
    4. 使用eslint-plugin-react-hooks检查依赖

代码示例

JavaScript JSX
// ❌ 闭包陷阱
useEffect(() => {
  const timer = setInterval(() => {
    console.log(count) // 永远是初始值
  }, 1000)
  return () => clearInterval(timer)
}, []) // count不在依赖项中

// ✅ 解决方案1:添加依赖
useEffect(() => {
  const timer = setInterval(() => {
    console.log(count)
  }, 1000)
  return () => clearInterval(timer)
}, [count])

// ✅ 解决方案2:使用函数式更新
useEffect(() => {
  const timer = setInterval(() => {
    setCount((c) => c + 1) // 不依赖外部count
  }, 1000)
  return () => clearInterval(timer)
}, [])

19. useInsertionEffect的作用是什么?

难度:⭐⭐⭐(高级) 标签:#useInsertionEffect #CSS-in-JS

问题描述: 介绍React 18新增的useInsertionEffect Hook。

参考答案要点

  • React 18新增Hook
  • 在DOM插入后立即同步执行
  • 主要用于CSS-in-JS库注入样式
  • 在所有DOM变更之前执行,比useLayoutEffect更早

20. useState返回的是数组而不是对象?

难度:⭐⭐(中级) 标签:#useState #解构赋值

问题描述: 解释为什么useState返回数组而不是对象。

参考答案要点

  • 数组解构可以自定义变量名:const [count, setCount] = useState(0)
  • 对象解构需要保持属性名一致
  • 数组解构更灵活,使用更方便
  • 多次调用useState时,数组解构可以任意命名

三、React 18/19新特性

React 18核心特性

1. React 18有哪些重要更新?

难度:⭐(基础) 标签:#React18 #新特性

问题描述: 概述React 18的重要更新内容。

参考答案要点

  • 并发渲染(Concurrent Rendering):允许React中断渲染,优先处理高优先级任务
  • 自动批处理(Automatic Batching):默认对所有更新进行批处理
  • 新的Root APIcreateRoot替代ReactDOM.render
  • Suspense支持SSR:服务端渲染支持Suspense
  • 新增Hooks:useId、useTransition、useDeferredValue、useSyncExternalStore、useInsertionEffect

2. 什么是并发渲染(Concurrent Rendering)?

难度:⭐⭐(中级) 标签:#并发渲染 #Fiber

问题描述: 详细解释并发渲染的概念和实现原理。

参考答案要点

  • 允许React中断渲染,优先处理高优先级任务
  • 基于Fiber架构时间切片实现
  • 用户交互(如输入)优先级高于列表渲染
  • 需要配合新API(useTransition、useDeferredValue)使用
  • 提高UI响应性,避免卡顿

3. 什么是自动批处理?

难度:⭐(基础) 标签:#自动批处理 #性能优化

问题描述: 解释React 18的自动批处理特性。

参考答案要点

  • React 18默认对所有更新进行批处理
  • 包括Promise、setTimeout、原生事件中的更新
  • 减少不必要的重新渲染
  • 使用flushSync可强制同步更新

代码示例

JavaScript JSX
// React 18自动批处理
setTimeout(() => {
  setCount((c) => c + 1)
  setFlag((f) => !f)
  // 合并为一次重新渲染
}, 1000)

4. React 18的createRoot和React 17的render有什么区别?

难度:⭐(基础) 标签:#createRoot #React18

问题描述: 比较React 18的createRoot和React 17的render API。

参考答案要点

  • createRoot启用并发特性
  • 支持新的API如useTransition
  • 更好的hydration支持

代码示例

JavaScript JSX
// React 17
import ReactDOM from "react-dom"
ReactDOM.render(<App />, document.getElementById("root"))

// React 18
import { createRoot } from "react-dom/client"
const root = createRoot(document.getElementById("root"))
root.render(<App />)

5. Suspense在React 18中有什么改进?

难度:⭐⭐(中级) 标签:#Suspense #SSR

问题描述: 介绍React 18中Suspense的改进。

参考答案要点

  • 支持服务端渲染的流式传输
  • 支持数据获取(配合React.lazy或数据获取库)
  • 与Error Boundary配合使用
  • 可以嵌套使用,实现更细粒度的加载状态

并发模式

6. useTransition的作用和使用场景?

难度:⭐⭐(中级) 标签:#useTransition #并发

问题描述: 介绍useTransition的作用和使用场景。

参考答案要点

  • 将状态更新标记为低优先级过渡
  • 返回[isPending, startTransition]
  • 适用于:搜索框输入、Tab切换、大量数据渲染
  • 保持UI响应性,避免卡顿

代码示例

JavaScript JSX
function SearchResults() {
  const [query, setQuery] = useState("")
  const [results, setResults] = useState([])
  const [isPending, startTransition] = useTransition()

  const handleChange = (e) => {
    const value = e.target.value
    setQuery(value) // 高优先级,立即更新
    startTransition(() => {
      setResults(search(value)) // 低优先级,可中断
    })
  }

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending && <Spinner />}
      <Results data={results} />
    </>
  )
}

7. useDeferredValue的作用和使用场景?

难度:⭐⭐(中级) 标签:#useDeferredValue #延迟更新

问题描述: 介绍useDeferredValue的作用和使用场景。

参考答案要点

  • 延迟某个值的更新
  • 类似于防抖,但由React控制
  • 适用于:延迟渲染列表、图表等非关键UI
  • 与useTransition的区别:useDeferredValue延迟值,useTransition控制更新

代码示例

JavaScript JSX
function SearchPage() {
  const [query, setQuery] = useState("")
  const deferredQuery = useDeferredValue(query)

  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      {/* 使用deferredQuery渲染搜索结果,延迟更新 */}
      <SearchResults query={deferredQuery} />
    </>
  )
}

8. useTransition和useDeferredValue有什么区别?

难度:⭐⭐(中级) 标签:#useTransition #useDeferredValue

问题描述: 比较useTransition和useDeferredValue的区别。

参考答案要点

特性useTransitionuseDeferredValue
作用对象状态更新单个值
触发方式手动包裹startTransition自动延迟
状态提示提供isPending需手动比较
适用场景复杂状态/组件加载搜索结果等非关键UI

9. startTransition和useTransition有什么关系?

难度:⭐⭐(中级) 标签:#startTransition #并发

问题描述: 解释startTransition和useTransition的关系。

参考答案要点

  • startTransition是独立函数
  • useTransition内部使用startTransition
  • startTransition可在事件处理器外使用
  • useTransition额外提供isPending状态

10. 什么是流式SSR(Streaming SSR)?

难度:⭐⭐⭐(高级) 标签:#StreamingSSR #服务端渲染

问题描述: 介绍流式SSR的概念和优势。

参考答案要点

  • 服务端分段发送HTML
  • 优先显示重要内容
  • 配合Suspense实现渐进式加载
  • 提高首屏加载体验

React 19新特性

11. React 19有哪些新特性?

难度:⭐⭐(中级) 标签:#React19 #新特性

问题描述: 概述React 19的新特性。

参考答案要点

  • Actions:支持async函数处理表单提交
  • 新Hooks:useOptimistic、useActionState、useFormStatus
  • React Compiler:自动优化渲染
  • RSC正式支持:React Server Components
  • use API:读取Promise或Context

12. 什么是React Compiler(原React Forget)?

难度:⭐⭐⭐(高级) 标签:#ReactCompiler #自动优化

问题描述: 介绍React Compiler的概念和作用。

参考答案要点

  • 自动记忆化编译器
  • 自动生成等效的useMemo/useCallback代码
  • 减少手动优化的需要
  • 通过AST分析依赖关系

13. useOptimistic的作用是什么?

难度:⭐⭐(中级) 标签:#useOptimistic #乐观更新

问题描述: 介绍React 19新增的useOptimistic Hook。

参考答案要点

  • React 19新增Hook
  • 实现乐观更新
  • 在异步操作完成前更新UI
  • 失败时自动回滚

14. useActionState的作用是什么?

难度:⭐⭐(中级) 标签:#useActionState #表单

问题描述: 介绍React 19新增的useActionState Hook。

参考答案要点

  • React 19新增Hook
  • 管理异步Action的状态
  • 返回[state, formAction, isPending]
  • 简化表单提交状态管理

15. use Hook的作用是什么?

难度:⭐⭐(中级) 标签:#use #React19 #Suspense

问题描述: 介绍React 19新增的use API。

参考答案要点

  • React 19新增API
  • 在渲染中读取Promise或Context
  • 配合Suspense使用
  • 简化异步数据获取

16. 什么是React Server Components(RSC)?

难度:⭐⭐⭐(高级) 标签:#RSC #服务端组件

问题描述: 详细解释React Server Components的概念和优势。

参考答案要点

  • 在服务端渲染的组件,不发送到客户端
  • 零客户端JS体积
  • 可直接访问服务端资源(数据库、文件系统等)
  • 与SSR区别:RSC不生成HTML,而是生成React元素树

17. React 18为什么放弃IE支持?

难度:⭐⭐(中级) 标签:#IE支持 #兼容性

问题描述: 解释React 18放弃IE支持的原因。

参考答案要点

  • 简化代码库
  • 使用现代浏览器特性(如Map、Set、requestIdleCallback)
  • 减少polyfill体积
  • 提高开发效率

18. React 18的Strict Mode有什么变化?

难度:⭐⭐(中级) 标签:#StrictMode #开发模式

问题描述: 介绍React 18中Strict Mode的变化。

参考答案要点

  • 开发模式下组件会故意双重渲染
  • 帮助检测副作用
  • 检测过时的生命周期方法
  • 为未来的并发特性做准备

四、状态管理

Context与Redux

1. Context API的优缺点是什么?

难度:⭐(基础) 标签:#Context #状态管理

问题描述: 分析Context API的优缺点。

参考答案要点优点

  • 内置,无需额外库
  • 适合跨层级传递数据

缺点

  • 性能问题:任何值变化导致所有消费者重渲染
  • 不适合高频更新

解决方案:拆分Context、使用useMemo缓存value


2. Redux的核心概念是什么?

难度:⭐(基础) 标签:#Redux #状态管理

问题描述: 介绍Redux的核心概念。

参考答案要点

  • Store:单一状态树
  • Action:描述发生了什么的普通对象
  • Reducer:纯函数,根据Action更新状态
  • 单向数据流:Action -> Reducer -> Store -> View

3. Redux中间件是什么?常用有哪些?

难度:⭐⭐(中级) 标签:#Redux #中间件

问题描述: 介绍Redux中间件的概念和常用中间件。

参考答案要点

  • 扩展dispatch功能
  • 常用:
    • redux-thunk:处理异步操作
    • redux-saga:处理复杂异步流程
    • redux-logger:日志记录
  • 中间件链式调用
  • 实现原理:柯里化函数

4. Redux Toolkit是什么?有什么优势?

难度:⭐⭐(中级) 标签:#ReduxToolkit #RTK

问题描述: 介绍Redux Toolkit及其优势。

参考答案要点

  • Redux官方推荐的工具集
  • 简化Redux配置和代码
  • 内置immer、redux-thunk、reselect
  • createSlice自动生成action creators和reducers

5. 如何避免Context的性能问题?

难度:⭐⭐(中级) 标签:#Context #性能优化

问题描述: 介绍避免Context性能问题的方法。

参考答案要点

  • 拆分多个小Context
  • 使用useMemo缓存Provider的value
  • 将状态拆分为原子化片段
  • 使用状态管理库(Zustand、Jotai)

现代状态管理方案

6. Zustand和Redux有什么区别?

难度:⭐⭐(中级) 标签:#Zustand #Redux

问题描述: 比较Zustand和Redux的区别。

参考答案要点

特性ReduxZustand
复杂度较高极简
学习成本
中间件丰富内置常用
代码量较多极少
TypeScript需配置原生支持

7. React Query/SWR的作用是什么?

难度:⭐⭐(中级) 标签:#ReactQuery #SWR #服务端状态

问题描述: 介绍React Query/SWR的作用。

参考答案要点

  • 服务端状态管理
  • 自动缓存、重新获取、后台更新
  • 处理加载、错误状态
  • 去重请求、乐观更新

8. 什么是不可变性(Immutability)?为什么重要?

难度:⭐⭐(中级) 标签:#不可变性 #状态管理

问题描述: 解释不可变性的概念及其重要性。

参考答案要点

  • 不直接修改数据,而是创建新数据
  • 便于比较变化(浅比较)
  • 支持时间旅行调试
  • React依赖不可变性进行优化

9. 什么是选择器(Selector)?

难度:⭐⭐(中级) 标签:#Selector #性能优化

问题描述: 介绍选择器的概念和作用。

参考答案要点

  • 从状态中提取派生数据
  • 使用reselect创建记忆化选择器
  • 避免重复计算
  • 组件只订阅需要的数据

10. 如何实现全局状态管理?

难度:⭐⭐(中级) 标签:#状态管理 #全局状态

问题描述: 列举实现全局状态管理的方法。

参考答案要点

  • Context + useReducer
  • Redux/Redux Toolkit
  • Zustand
  • Jotai/Recoil(原子化)
  • MobX(响应式)

11. 什么是乐观更新(Optimistic Update)?

难度:⭐⭐(中级) 标签:#乐观更新 #用户体验

问题描述: 解释乐观更新的概念和实现方式。

参考答案要点

  • 先更新UI,再发送请求
  • 失败时回滚
  • 提升用户体验
  • React Query/useOptimistic支持

12. 状态应该放在哪里?

难度:⭐⭐(中级) 标签:#状态管理 #最佳实践

问题描述: 介绍状态放置的原则。

参考答案要点

  • 优先放在使用它的组件
  • 需要共享时提升到共同祖先
  • 全局状态使用状态管理库
  • 服务端状态使用React Query/SWR

13. 什么是派生状态(Derived State)?

难度:⭐⭐(中级) 标签:#派生状态 #状态管理

问题描述: 解释派生状态的概念。

参考答案要点

  • 可以从props或state计算得出的状态
  • 避免重复存储
  • 使用useMemo或选择器计算
  • 避免getDerivedStateFromProps滥用

14. 如何处理表单状态?

难度:⭐⭐(中级) 标签:#表单 #状态管理

问题描述: 介绍表单状态处理的方法。

参考答案要点

  • 受控组件管理每个字段
  • 使用表单库:React Hook Form、Formik
  • 分离表单状态和UI状态
  • 惰性验证优化性能

15. 什么是原子化状态管理(Jotai/Recoil)?

难度:⭐⭐⭐(高级) 标签:#Jotai #Recoil #原子化

问题描述: 介绍原子化状态管理的概念。

参考答案要点

  • 状态拆分为独立原子
  • 组件只订阅需要的原子
  • 自动依赖追踪
  • 细粒度更新,避免不必要的重渲染

五、性能优化

渲染优化

1. React.memo的作用是什么?

难度:⭐(基础) 标签:#React.memo #性能优化

问题描述: 介绍React.memo的作用和使用场景。

参考答案要点

  • 高阶组件,缓存函数组件
  • props浅比较,不变则不重渲染
  • 可自定义比较函数
  • 适用于纯展示组件

代码示例

JavaScript JSX
const MyComponent = React.memo(
  function MyComponent({ name }) {
    return <div>{name}</div>
  },
  (prevProps, nextProps) => {
    // 自定义比较函数
    return prevProps.name === nextProps.name
  }
)

2. 什么时候应该使用useMemo和useCallback?

难度:⭐⭐(中级) 标签:#useMemo #useCallback #性能优化

问题描述: 介绍useMemo和useCallback的适用场景。

参考答案要点

  • 计算成本高的值使用useMemo
  • 传递给子组件的函数使用useCallback
  • 依赖数组要正确填写
  • 不要滥用,缓存也有开销

3. 如何实现代码分割和懒加载?

难度:⭐⭐(中级) 标签:#代码分割 #懒加载 #Suspense

问题描述: 介绍代码分割和懒加载的实现方法。

参考答案要点

  • 使用React.lazy和动态import
  • 配合Suspense显示加载状态
  • 路由级别分割

代码示例

JavaScript JSX
const LazyComponent = React.lazy(() => import("./LazyComponent"))

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <LazyComponent />
    </Suspense>
  )
}

4. 什么是虚拟列表?如何实现?

难度:⭐⭐(中级) 标签:#虚拟列表 #大数据

问题描述: 介绍虚拟列表的概念和实现方法。

参考答案要点

  • 只渲染可视区域的元素
  • 使用react-window或react-virtualized
  • 适合大数据量列表
  • 减少DOM节点数量

5. 如何排查组件不必要的重复渲染?

难度:⭐⭐(中级) 标签:#性能优化 #调试

问题描述: 介绍排查组件重复渲染的方法。

参考答案要点

  • React DevTools Profiler
  • 使用memo、useMemo、useCallback
  • 检查依赖数组
  • 拆分组件,缩小重渲染范围

6. 什么是shouldComponentUpdate?

难度:⭐⭐(中级) 标签:#shouldComponentUpdate #类组件

问题描述: 介绍shouldComponentUpdate的作用。

参考答案要点

  • 类组件生命周期方法
  • 控制是否重新渲染
  • 返回false阻止渲染
  • PureComponent自动实现浅比较

代码优化

7. 如何避免在渲染中创建新对象/函数?

难度:⭐⭐(中级) 标签:#性能优化 #渲染优化

问题描述: 介绍避免渲染中创建新对象/函数的方法。

参考答案要点

  • 使用useMemo缓存对象
  • 使用useCallback缓存函数
  • 避免内联函数定义
  • 将常量移到组件外部

8. 什么是时间切片(Time Slicing)?

难度:⭐⭐⭐(高级) 标签:#时间切片 #并发

问题描述: 介绍时间切片的概念和实现原理。

参考答案要点

  • 将大任务拆分为小任务
  • 在浏览器空闲时执行
  • 基于requestIdleCallback
  • React 18并发特性基础

9. 如何优化大型应用的启动时间?

难度:⭐⭐⭐(高级) 标签:#性能优化 #启动优化

问题描述: 介绍优化大型应用启动时间的方法。

参考答案要点

  • 代码分割和懒加载
  • Tree Shaking移除无用代码
  • 压缩和Gzip
  • CDN分发
  • 服务端渲染

10. 什么是Web Worker?在React中如何使用?

难度:⭐⭐⭐(高级) 标签:#WebWorker #性能优化

问题描述: 介绍Web Worker的概念和在React中的使用。

参考答案要点

  • 在后台线程运行JavaScript
  • 不阻塞主线程
  • 适合复杂计算
  • 使用comlink简化通信

11. 如何优化图片加载?

难度:⭐⭐(中级) 标签:#图片优化 #性能优化

问题描述: 介绍优化图片加载的方法。

参考答案要点

  • 使用next/image或react-lazy-load-image-component
  • 懒加载非首屏图片
  • 使用WebP格式
  • 响应式图片
  • 预加载关键图片

12. 什么是Hydration?如何优化?

难度:⭐⭐⭐(高级) 标签:#Hydration #SSR

问题描述: 介绍Hydration的概念和优化方法。

参考答案要点

  • 服务端渲染后客户端激活
  • 不匹配会导致重新渲染
  • 确保服务端和客户端输出一致
  • 使用suppressHydrationWarning

13. 如何使用Profiler进行性能分析?

难度:⭐⭐(中级) 标签:#Profiler #性能分析

问题描述: 介绍Profiler的使用方法。

参考答案要点

  • 测量组件渲染时间
  • 识别性能瓶颈
  • 只在开发模式使用

代码示例

JavaScript JSX
;<Profiler id="App" onRender={onRenderCallback}>
  <App />
</Profiler>

function onRenderCallback(id, phase, actualDuration) {
  console.log("Component:", id)
  console.log("Phase:", phase)
  console.log("Duration:", actualDuration)
}

14. 什么是CSS-in-JS的性能影响?

难度:⭐⭐(中级) 标签:#CSS-in-JS #性能优化

问题描述: 介绍CSS-in-JS的性能影响和优化方法。

参考答案要点

  • 运行时生成CSS有开销
  • 使用useInsertionEffect注入样式
  • 考虑静态CSS方案
  • 避免动态生成大量样式

15. key属性在列表渲染中的作用?

难度:⭐(基础) 标签:#Key #列表渲染

问题描述: 介绍key属性在列表渲染中的作用。

参考答案要点

  • 帮助React识别元素身份
  • 优化Diff算法
  • 稳定的key减少不必要的重建
  • 避免使用数组索引作为key

六、React Router v6

1. React Router v6有哪些重大变化?

难度:⭐(基础) 标签:#ReactRouter #v6

问题描述: 介绍React Router v6的重大变化。

参考答案要点

  • Switch替换为Routes
  • Route使用element而非component
  • 嵌套路由配置更简洁
  • 移除Redirect,使用Navigate
  • 默认精确匹配,移除exact

2. BrowserRouter和HashRouter的区别?

难度:⭐(基础) 标签:#BrowserRouter #HashRouter

问题描述: 比较BrowserRouter和HashRouter的区别。

参考答案要点

  • BrowserRouter:使用History API,URL美观,需要服务端配置
  • HashRouter:使用URL hash,兼容性好,URL有#
  • 推荐使用BrowserRouter

3. 如何实现路由鉴权?

难度:⭐⭐(中级) 标签:#路由鉴权 #权限控制

问题描述: 介绍路由鉴权的实现方法。

参考答案要点

  • 高阶组件或自定义路由组件
  • 检查用户权限
  • 未登录重定向到登录页

代码示例

JavaScript JSX
function PrivateRoute({ children }) {
  const isAuth = useAuth()
  return isAuth ? children : <Navigate to="/login" />
}

// 使用
;<Route
  path="/dashboard"
  element={
    <PrivateRoute>
      <Dashboard />
    </PrivateRoute>
  }
/>

4. useNavigate和useHistory有什么区别?

难度:⭐(基础) 标签:#useNavigate #路由导航

问题描述: 比较useNavigate和useHistory的区别。

参考答案要点

  • useHistory是v5的API
  • useNavigate是v6的新API
  • navigate支持相对路径
  • 更简洁的API设计

5. 如何实现嵌套路由?

难度:⭐⭐(中级) 标签:#嵌套路由 #Outlet

问题描述: 介绍嵌套路由的实现方法。

参考答案要点

  • 使用Outlet渲染子路由
  • 配置嵌套路由结构

代码示例

JavaScript JSX
;<Route path="/users" element={<Users />}>
  <Route path=":id" element={<UserDetail />} />
</Route>

// Users组件中使用Outlet
import { Outlet } from "react-router-dom"
function Users() {
  return (
    <div>
      <h1>Users</h1>
      <Outlet /> {/* 子路由渲染位置 */}
    </div>
  )
}

6. 如何获取路由参数?

难度:⭐(基础) 标签:#路由参数 #useParams

问题描述: 介绍获取路由参数的方法。

参考答案要点

  • useParams:获取动态路由参数
  • useSearchParams:获取查询参数
  • useLocation:获取完整location对象

7. 如何实现路由懒加载?

难度:⭐⭐(中级) 标签:#路由懒加载 #代码分割

问题描述: 介绍路由懒加载的实现方法。

代码示例

JavaScript JSX
const Dashboard = lazy(() => import("./Dashboard"))

;<Route
  path="/dashboard"
  element={
    <Suspense fallback={<Loading />}>
      <Dashboard />
    </Suspense>
  }
/>

8. 什么是数据路由(Data Router)?

难度:⭐⭐⭐(高级) 标签:#DataRouter #ReactRouter

问题描述: 介绍React Router v6.4+的数据路由特性。

参考答案要点

  • React Router v6.4+特性
  • 并行加载数据和组件
  • 解决瀑布流问题
  • 使用loader和action

9. 如何实现路由守卫?

难度:⭐⭐(中级) 标签:#路由守卫 #权限控制

问题描述: 介绍路由守卫的实现方法。

参考答案要点

  • 自定义ProtectedRoute组件
  • 在layout中统一处理
  • 使用高阶组件
  • 服务端鉴权配合

10. 编程式导航和声明式导航的区别?

难度:⭐(基础) 标签:#导航 #ReactRouter

问题描述: 比较编程式导航和声明式导航的区别。

参考答案要点

  • 声明式:Link、NavLink组件
  • 编程式:useNavigate钩子
  • 声明式适合模板中
  • 编程式适合事件处理中

11. 如何处理404页面?

难度:⭐(基础) 标签:#404 #路由配置

问题描述: 介绍404页面的处理方法。

参考答案要点

  • 使用*通配符
  • 放在所有路由最后
  • 可配合Navigate重定向

代码示例

JavaScript JSX
<Route path="*" element={<NotFound />} />

12. 如何实现路由动画?

难度:⭐⭐(中级) 标签:#路由动画 #动画

问题描述: 介绍路由动画的实现方法。

参考答案要点

  • 使用react-transition-group
  • 或framer-motion
  • 配合location.key
  • 注意动画性能

七、服务端渲染(Next.js)

1. 什么是SSR、SSG、ISR?

难度:⭐(基础) 标签:#SSR #SSG #ISR

问题描述: 介绍SSR、SSG、ISR的概念和区别。

参考答案要点

模式说明适用场景
SSR服务端渲染,每次请求生成实时数据、个性化
SSG静态生成,构建时生成内容不变、博客
ISR增量静态再生,定时更新商品列表、新闻

2. Next.js App Router和Pages Router的区别?

难度:⭐⭐(中级) 标签:#Next.js #AppRouter

问题描述: 比较Next.js App Router和Pages Router的区别。

参考答案要点

  • App Router基于文件夹路由
  • 默认使用React Server Components
  • 更强大的嵌套布局
  • 支持平行路由、拦截路由
  • 数据获取方式不同

3. 什么是React Server Components?

难度:⭐⭐⭐(高级) 标签:#RSC #服务端组件

问题描述: 介绍React Server Components的概念。

参考答案要点

  • 服务端渲染的组件
  • 零客户端JS
  • 可直接访问服务端资源
  • 与客户端组件配合使用

4. 如何在Next.js中实现ISR?

难度:⭐⭐(中级) 标签:#ISR #Next.js

问题描述: 介绍Next.js中ISR的实现方法。

代码示例

JavaScript JSX
// pages router
export async function getStaticProps() {
  return {
    props: { data },
    revalidate: 60, // 60秒后重新生成
  }
}

// app router
export const revalidate = 60

5. 什么是Streaming SSR?

难度:⭐⭐⭐(高级) 标签:#StreamingSSR #Next.js

问题描述: 介绍Streaming SSR的概念。

参考答案要点

  • 分段发送HTML
  • 配合Suspense
  • 优先显示重要内容
  • 提高感知性能

6. 如何在App Router中获取数据?

难度:⭐⭐(中级) 标签:#数据获取 #AppRouter

问题描述: 介绍App Router中的数据获取方法。

代码示例

JavaScript JSX
// Server Component
async function Page() {
  const data = await fetch("https://api.example.com/data")
  return <Component data={data} />
}

参考答案要点

  • 直接在组件中使用async/await
  • 自动去重相同请求
  • 支持缓存配置

7. 什么是Server Actions?

难度:⭐⭐(中级) 标签:#ServerActions #Next.js

问题描述: 介绍Next.js 14+的Server Actions特性。

参考答案要点

  • Next.js 14+特性
  • 服务端执行的函数
  • 可直接在表单中使用
  • 简化数据变更逻辑

8. 如何处理客户端和服务端的不一致?

难度:⭐⭐⭐(高级) 标签:#Hydration #SSR

问题描述: 介绍处理客户端和服务端不一致的方法。

参考答案要点

  • 避免在服务端使用浏览器API
  • 使用dynamic导入禁用SSR
  • 使用suppressHydrationWarning
  • 确保数据一致性

9. 什么是Middleware?

难度:⭐⭐(中级) 标签:#Middleware #Next.js

问题描述: 介绍Next.js Middleware的概念和用途。

参考答案要点

  • 请求处理中间件
  • 实现认证、重定向、AB测试
  • 在matcher匹配的路由前执行
  • 边缘运行,快速响应

10. 如何优化Next.js应用性能?

难度:⭐⭐(中级) 标签:#性能优化 #Next.js

问题描述: 介绍优化Next.js应用性能的方法。

参考答案要点

  • 使用Image组件优化图片
  • 使用Font组件优化字体
  • 代码分割和懒加载
  • 合理使用缓存策略
  • 分析bundle大小

11. 什么是Partial Prerendering(PPR)?

难度:⭐⭐⭐(高级) 标签:#PPR #Next.js

问题描述: 介绍Next.js 14+的Partial Prerendering特性。

参考答案要点

  • Next.js 14+实验性功能
  • 静态外壳+动态内容
  • 结合SSG和SSR优势
  • 提高首屏加载速度

12. 如何实现国际化路由?

难度:⭐⭐(中级) 标签:#国际化 #i18n

问题描述: 介绍Next.js中国际化路由的实现方法。

参考答案要点

  • 使用next-intl或i18next
  • App Router内置支持
  • 配置locales和defaultLocale
  • 中间件处理语言切换

13. 什么是Route Handlers?

难度:⭐⭐(中级) 标签:#RouteHandlers #API

问题描述: 介绍App Router中的Route Handlers。

参考答案要点

  • App Router中替代API Routes
  • 在app目录下创建route.js
  • 支持各种HTTP方法
  • 类型安全

14. 如何使用Parallel Routes?

难度:⭐⭐⭐(高级) 标签:#ParallelRoutes #AppRouter

问题描述: 介绍Parallel Routes的使用方法。

参考答案要点

  • 使用@folder语法
  • 同一页面显示多个路由
  • 实现复杂布局
  • 独立加载状态

15. 什么是Intercepting Routes?

难度:⭐⭐⭐(高级) 标签:#InterceptingRoutes #路由拦截

问题描述: 介绍Intercepting Routes的概念。

参考答案要点

  • 拦截路由导航
  • 实现模态框效果
  • 使用(.) (..) (...)语法
  • 保留上下文

八、测试

1. React Testing Library的核心理念是什么?

难度:⭐(基础) 标签:#TestingLibrary #测试理念

问题描述: 介绍React Testing Library的核心理念。

参考答案要点

  • 测试用户如何与UI交互
  • 不测试实现细节
  • 可访问性优先的查询
  • 鼓励更好的可访问性实践

2. 如何测试React组件?

难度:⭐(基础) 标签:#组件测试 #TestingLibrary

问题描述: 介绍React组件的测试方法。

代码示例

JavaScript JSX
import { render, screen, fireEvent } from "@testing-library/react"

test("button click increments counter", () => {
  render(<Counter />)
  const button = screen.getByText("Increment")
  fireEvent.click(button)
  expect(screen.getByText("1")).toBeInTheDocument()
})

3. 什么是Mock?在测试中如何使用?

难度:⭐⭐(中级) 标签:#Mock #测试

问题描述: 介绍Mock的概念和使用方法。

参考答案要点

  • 模拟函数或模块
  • jest.fn()创建mock函数
  • jest.mock()模拟模块
  • 控制返回值和验证调用

4. 如何测试异步操作?

难度:⭐⭐(中级) 标签:#异步测试 #TestingLibrary

问题描述: 介绍异步操作的测试方法。

代码示例

JavaScript JSX
import { waitFor } from "@testing-library/react"

test("fetches data", async () => {
  render(<DataComponent />)
  await waitFor(() => {
    expect(screen.getByText("Data loaded")).toBeInTheDocument()
  })
})

5. 什么是MSW(Mock Service Worker)?

难度:⭐⭐(中级) 标签:#MSW #API模拟

问题描述: 介绍MSW的概念和用途。

参考答案要点

  • 拦截网络请求
  • 在浏览器和Node中运行
  • 模拟API响应
  • 不修改应用代码

6. 如何测试Hooks?

难度:⭐⭐(中级) 标签:#Hooks测试 #renderHook

问题描述: 介绍Hooks的测试方法。

代码示例

JavaScript JSX
import { renderHook, act } from "@testing-library/react-hooks"

test("useCounter", () => {
  const { result } = renderHook(() => useCounter())
  act(() => {
    result.current.increment()
  })
  expect(result.current.count).toBe(1)
})

7. 什么是快照测试?

难度:⭐(基础) 标签:#快照测试 #回归测试

问题描述: 介绍快照测试的概念和使用场景。

参考答案要点

  • 比较当前输出与保存的快照
  • 适合UI组件回归测试
  • 更新快照:--updateSnapshot
  • 谨慎使用,避免过度依赖

8. 如何测试表单?

难度:⭐⭐(中级) 标签:#表单测试 #user-event

问题描述: 介绍表单的测试方法。

参考答案要点

  • 使用user-event模拟用户输入
  • 测试验证逻辑
  • 测试提交处理
  • 测试错误状态

9. 什么是E2E测试?常用工具有哪些?

难度:⭐(基础) 标签:#E2E测试 #端到端

问题描述: 介绍E2E测试的概念和常用工具。

参考答案要点

  • 端到端测试,模拟真实用户操作
  • 常用工具:Cypress、Playwright、Selenium
  • 测试完整用户流程
  • 较慢但覆盖全面

10. 如何测试Context Provider?

难度:⭐⭐(中级) 标签:#Context测试 #Provider

问题描述: 介绍Context Provider的测试方法。

代码示例

JavaScript JSX
const wrapper = ({ children }) => (
  <ThemeProvider theme="dark">{children}</ThemeProvider>
)

render(<Component />, { wrapper })

九、源码原理

Fiber架构

1. 什么是Fiber架构?

难度:⭐⭐⭐(高级) 标签:#Fiber #架构

问题描述: 介绍React Fiber架构的概念和设计目标。

参考答案要点

  • React 16引入的新协调引擎
  • 将渲染工作拆分为小单元
  • 支持优先级调度和可中断渲染
  • Fiber节点是链表结构

2. Fiber节点的数据结构是怎样的?

难度:⭐⭐⭐(高级) 标签:#Fiber #数据结构

问题描述: 介绍Fiber节点的数据结构。

代码示例

JAVASCRIPT
function FiberNode() {
  this.tag = tag // 组件类型
  this.key = key // 唯一标识
  this.type = null // 元素类型
  this.stateNode = null // 真实DOM或组件实例
  this.return = null // 父节点
  this.child = null // 第一个子节点
  this.sibling = null // 下一个兄弟节点
  this.alternate = null // 双缓冲树对应节点
  this.lanes = NoLanes // 更新优先级
}

3. React的渲染流程是怎样的?

难度:⭐⭐⭐(高级) 标签:#渲染流程 #Fiber

问题描述: 详细介绍React的渲染流程。

参考答案要点

1. Render阶段(可中断)

  • 构建Fiber树
  • 执行Diff算法
  • 标记副作用

2. Commit阶段(不可中断)

  • 执行DOM操作
  • 执行生命周期和副作用
  • 更新refs

4. 什么是Lane模型?

难度:⭐⭐⭐(高级) 标签:#Lane #优先级

问题描述: 介绍React的Lane模型。

参考答案要点

  • 位掩码表示优先级
  • 不同Lane代表不同优先级
  • SyncLane最高优先级
  • TransitionLane低优先级
  • 支持批量合并

调度与渲染

5. React的调度机制是怎样的?

难度:⭐⭐⭐(高级) 标签:#Scheduler #调度

问题描述: 介绍React的调度机制。

参考答案要点

  • 使用Scheduler包
  • MessageChannel实现微任务
  • 时间切片防止阻塞
  • 优先级队列管理任务

6. 什么是双缓冲(Double Buffering)?

难度:⭐⭐⭐(高级) 标签:#双缓冲 #Fiber

问题描述: 介绍React的双缓冲机制。

参考答案要点

  • 两棵Fiber树交替使用
  • current树:当前屏幕显示
  • workInProgress树:正在构建
  • 提交后交换指针

7. React为什么不使用requestIdleCallback?

难度:⭐⭐⭐(高级) 标签:#Scheduler #requestIdleCallback

问题描述: 解释React为什么不使用requestIdleCallback。

参考答案要点

  • requestIdleCallback兼容性差
  • 调度不可控
  • 使用MessageChannel实现更可控的调度
  • 自定义Scheduler更灵活

8. 什么是时间切片(Time Slicing)?

难度:⭐⭐⭐(高级) 标签:#时间切片 #并发

问题描述: 介绍React的时间切片机制。

参考答案要点

  • 将大任务拆分为小任务
  • 每个任务执行后检查剩余时间
  • 时间不足则让出主线程
  • 使用shouldYield判断

9. React的Diff算法具体是如何工作的?

难度:⭐⭐⭐(高级) 标签:#Diff算法 #源码

问题描述: 详细介绍React Diff算法的实现。

参考答案要点

  • 单节点Diff:比较type和key
  • 多节点Diff:两轮遍历
    • 第一轮:复用相同位置的节点
    • 第二轮:处理移动、新增、删除
  • key优化列表对比

10. 什么是Reconciliation?

难度:⭐⭐⭐(高级) 标签:#Reconciliation #协调

问题描述: 介绍React的Reconciliation过程。

参考答案要点

  • 协调过程:比较新旧虚拟DOM
  • 确定需要更新的部分
  • 生成更新计划
  • 不直接操作DOM

11. React的合成事件系统是如何实现的?

难度:⭐⭐⭐(高级) 标签:#合成事件 #事件系统

问题描述: 介绍React合成事件系统的实现。

参考答案要点

  • 事件委托到root容器
  • 统一封装SyntheticEvent
  • 事件池复用(React 17前)
  • 模拟事件冒泡

12. 什么是Hooks的调用顺序规则?

难度:⭐⭐⭐(高级) 标签:#Hooks #源码

问题描述: 深入解释Hooks的调用顺序规则。

参考答案要点

  • 基于数组/链表实现
  • 按调用顺序存储状态
  • 条件调用导致顺序错乱
  • ESLint插件强制执行

13. useState是如何实现的?

难度:⭐⭐⭐(高级) 标签:#useState #源码

问题描述: 介绍useState的实现原理。

参考答案要点

  • 基于链表存储状态
  • 每个Hook对应一个节点
  • 通过next指针连接
  • 渲染时按顺序访问

14. 什么是优先级调度?

难度:⭐⭐⭐(高级) 标签:#优先级 #调度

问题描述: 介绍React的优先级调度机制。

参考答案要点

  • 不同更新有不同优先级
  • 用户交互 > 动画 > 数据加载
  • 高优先级可中断低优先级
  • Lane模型实现

15. React 18的并发特性是如何实现的?

难度:⭐⭐⭐(高级) 标签:#并发 #React18 #源码

问题描述: 介绍React 18并发特性的实现原理。

参考答案要点

  • Fiber架构支持可中断渲染
  • Lane模型管理优先级
  • 时间切片分配任务
  • startTransition标记低优先级

十、高级特性与其他

1. 什么是高阶组件(HOC)?

难度:⭐⭐(中级) 标签:#HOC #高阶组件

问题描述: 介绍高阶组件的概念和使用场景。

参考答案要点

  • 接收组件返回新组件的函数
  • 用于代码复用和逻辑抽象
  • 不修改原组件,而是包装
  • 常见用途:权限控制、数据获取、日志记录

2. 什么是Render Props模式?

难度:⭐⭐(中级) 标签:#RenderProps #模式

问题描述: 介绍Render Props模式的概念。

参考答案要点

  • 通过props传递渲染函数
  • 共享组件逻辑
  • 与HOC相比更灵活
  • 可能产生嵌套地狱

3. HOC和Render Props有什么区别?

难度:⭐⭐(中级) 标签:#HOC #RenderProps #比较

问题描述: 比较HOC和Render Props的区别。

参考答案要点

特性HOCRender Props
实现方式函数包装props传递函数
嵌套问题可能有可能有
灵活性较低较高
TypeScript类型推断较难类型推断较好

4. 什么是自定义Hook的封装原则?

难度:⭐⭐(中级) 标签:#自定义Hook #封装

问题描述: 介绍自定义Hook的封装原则。

参考答案要点

  • 以use开头命名
  • 一个Hook只做一件事
  • 合理拆分,保持单一职责
  • 提供清晰的API和文档

5. 如何实现组件级别的权限控制?

难度:⭐⭐(中级) 标签:#权限控制 #HOC

问题描述: 介绍组件级别权限控制的实现方法。

代码示例

JavaScript JSX
function withAuth(Component) {
  return function WrappedComponent(props) {
    const isAuth = useAuth()
    if (!isAuth) return <Navigate to="/login" />
    return <Component {...props} />
  }
}

6. 什么是微前端?在React中如何实现?

难度:⭐⭐⭐(高级) 标签:#微前端 #架构

问题描述: 介绍微前端的概念和在React中的实现。

参考答案要点

  • 将大型应用拆分为独立部署的小应用
  • 实现方案:qiankun、Module Federation、single-spa
  • 样式隔离、JS沙箱
  • 共享依赖

7. React中的Refs有哪些使用方式?

难度:⭐(基础) 标签:#Refs #DOM操作

问题描述: 介绍React中Refs的使用方式。

参考答案要点

  • createRef:类组件使用
  • useRef:函数组件使用
  • callback ref:回调方式
  • forwardRef:转发ref到子组件

8. 如何实现KeepAlive功能?

难度:⭐⭐⭐(高级) 标签:#KeepAlive #状态保持

问题描述: 介绍KeepAlive功能的实现方法。

参考答案要点

  • React不原生支持
  • 使用display:none隐藏
  • 或使用第三方库react-activation
  • 维护组件状态不被销毁

9. 什么是React的严格模式(Strict Mode)?

难度:⭐(基础) 标签:#StrictMode #开发模式

问题描述: 介绍React严格模式的作用。

参考答案要点

  • 开发模式下检测潜在问题
  • 故意双重渲染检测副作用
  • 检测过时的生命周期
  • 检测意外的副作用

10. React和Vue的设计哲学有什么区别?

难度:⭐⭐(中级) 标签:#React #Vue #比较

问题描述: 比较React和Vue的设计哲学。

参考答案要点

特性ReactVue
核心思想函数式、不可变响应式、可变
模板JSX模板语法
状态管理手动管理自动追踪依赖
学习曲线较陡较平缓
灵活性中高

附录:手写代码题精选

1. 实现简版useState

JAVASCRIPT
let hookIndex = 0
const hooks = []

function useState(initialValue) {
  const state = hooks[hookIndex] !== undefined ? hooks[hookIndex] : initialValue
  hooks[hookIndex] = state
  const currentIndex = hookIndex
  hookIndex++

  const setState = (newValue) => {
    hooks[currentIndex] = newValue
    render() // 触发重新渲染
  }

  return [state, setState]
}

function render() {
  hookIndex = 0
  // 重新渲染组件
}

2. 实现简版useEffect

JAVASCRIPT
let effectIndex = 0
const effectDeps = []

function useEffect(callback, deps) {
  const hasChanged =
    !deps ||
    !effectDeps[effectIndex] ||
    !deps.every((dep, i) => dep === effectDeps[effectIndex][i])

  if (hasChanged) {
    callback()
    effectDeps[effectIndex] = deps || []
  }
  effectIndex++
}

3. 实现自定义useDebounce

JAVASCRIPT
function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value)

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay)
    return () => clearTimeout(timer)
  }, [value, delay])

  return debouncedValue
}

4. 实现自定义useFetch

JAVASCRIPT
function useFetch(url) {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  useEffect(() => {
    setLoading(true)
    fetch(url)
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
      .catch((err) => {
        setError(err)
        setLoading(false)
      })
  }, [url])

  return { data, loading, error }
}

5. 实现自定义useLocalStorage

JAVASCRIPT
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const item = localStorage.getItem(key)
      return item ? JSON.parse(item) : initialValue
    } catch {
      return initialValue
    }
  })

  useEffect(() => {
    try {
      localStorage.setItem(key, JSON.stringify(value))
    } catch (error) {
      console.error("Error saving to localStorage:", error)
    }
  }, [key, value])

  return [value, setValue]
}

复习建议与重点题目

复习建议

  1. 分阶段复习

    • 第一阶段:掌握基础概念(⭐题目)
    • 第二阶段:深入Hooks和组件通信(⭐⭐题目)
    • 第三阶段:理解源码原理和高级特性(⭐⭐⭐题目)
  2. 动手实践

    • 手写常用Hooks(useDebounce、useFetch等)
    • 实现小型React项目
    • 阅读React源码关键部分
  3. 面试技巧

    • 回答时先给出概念定义
    • 结合实际项目经验说明
    • 主动提及优缺点和适用场景
    • 准备代码示例

重点题目推荐

🔴 必会题目(面试高频)

题目难度重要性
useState和useEffect的工作原理⭐⭐⭐⭐⭐⭐⭐
useEffect依赖项数组的作用⭐⭐⭐⭐⭐
useMemo和useCallback的区别⭐⭐⭐⭐⭐⭐⭐
React.memo的作用⭐⭐⭐⭐⭐
setState是同步还是异步⭐⭐⭐⭐⭐⭐⭐
虚拟DOM和Diff算法⭐⭐⭐⭐⭐⭐⭐⭐
React 18并发特性⭐⭐⭐⭐⭐⭐
Hooks的闭包陷阱⭐⭐⭐⭐⭐⭐⭐

🔵 进阶题目(大厂常问)

题目难度重要性
Fiber架构原理⭐⭐⭐⭐⭐⭐⭐
Lane模型⭐⭐⭐⭐⭐⭐⭐
React Compiler⭐⭐⭐⭐⭐⭐
React Server Components⭐⭐⭐⭐⭐⭐⭐

🟢 加分题目(展示深度)

题目难度重要性
时间切片实现⭐⭐⭐⭐⭐⭐
优先级调度⭐⭐⭐⭐⭐⭐
useInsertionEffect⭐⭐⭐⭐⭐⭐

最后更新于: 2026-02-27