React相关面试题

React 高频面试题(2026版):基础+进阶+手写+项目实战全覆盖

结合最新面试趋势(React 18、Hooks 最佳实践、服务端渲染),整理了分梯度、带答题思路、附手写代码的核心面试题,覆盖入门到资深级考点,帮你精准抓住重点、高效备考。

一、基础必懂(入门级,80%面试会问)

1. React 的核心特性有哪些?

核心答案

  • 声明式编程:关注"做什么"而非"怎么做",只需描述UI状态,React 自动处理DOM更新;
  • 组件化:UI拆分为独立可复用的组件,降低耦合、提升维护性;
  • 单向数据流:数据从父组件流向子组件,子组件不直接修改父组件数据,保证数据可追溯;
  • 虚拟DOM(VDOM):用JS对象描述DOM结构,通过diff算法最小化DOM操作;
  • JSX :语法糖(React.createElement的简写),允许在JS中写HTML结构,提升开发效率。

2. JSX 是什么?为什么不能直接运行,需要编译?

核心答案

  • JSX 是 React 的语法扩展,本质是 React.createElement(component, props, ...children) 的语法糖;
  • 示例:<div className="box">Hello</div> 编译后 → React.createElement('div', { className: 'box' }, 'Hello')
  • 不能直接运行的原因:浏览器无法识别JSX语法,需通过Babel编译为普通JS代码后才能执行。

3. React 组件的两种定义方式及区别?

维度 函数组件(Function Component) 类组件(Class Component)
写法 纯函数,返回JSX 继承React.Component,通过render返回JSX
状态管理 需用Hooks(useState/useReducer) 用this.state/this.setState
生命周期 需用Hooks(useEffect) 内置生命周期方法(componentDidMount等)
性能 更轻量,无实例开销 有实例开销,略重
TS支持 更简洁,类型推断友好 需绑定this,类型配置复杂
适用场景 大部分场景(React16.8+推荐) 老项目/需复杂生命周期场景

4. 简述 React 的单向数据流及优势

核心答案

  • 单向数据流:数据只能从父组件通过props传递给子组件,子组件若要修改数据,需调用父组件传递的回调函数,由父组件更新数据后再回传;
  • 优势:
    1. 数据流向清晰,便于调试(可快速定位数据修改位置);
    2. 避免子组件随意修改数据导致的状态混乱;
    3. 组件解耦,父组件控制数据,子组件仅负责展示/交互。

5. props 和 state 的区别?

维度 props state
来源 父组件传递 组件内部定义
可变性 只读(子组件不能修改) 可变(通过setState/useState更新)
触发更新 父组件修改props,子组件重新渲染 组件内部更新state,自身重新渲染
用途 组件间通信 组件内部状态管理

二、Hooks 核心(中级,高频区分度考点)

1. React Hooks 出现的背景?解决了什么问题?

核心答案

  • 背景:类组件存在的痛点------
    1. 逻辑复用困难(HOC/Render Props 导致嵌套地狱);
    2. 复杂组件逻辑分散(生命周期方法中混杂不同逻辑,如componentDidMount同时请求数据+初始化定时器);
    3. this指向问题(类组件方法需绑定this,易出错);
  • 解决的问题:
    1. 用Hooks将分散的逻辑聚合,按功能组织代码;
    2. 函数组件支持状态管理和生命周期逻辑;
    3. 逻辑复用更简洁(自定义Hooks),无嵌套地狱;
    4. 无需处理this指向问题。

2. 常用 Hooks 及使用场景(useState/useEffect/useRef/useMemo/useCallback)

Hook 核心作用 典型使用场景
useState 函数组件声明状态 管理组件内部简单状态(如输入框值、弹窗显隐)
useEffect 处理副作用(数据请求/定时器/事件绑定) 组件挂载请求数据、卸载清理定时器/事件监听
useRef 保存可变值(不触发渲染) 获取DOM元素、保存定时器ID、缓存上一次状态
useMemo 缓存计算结果(避免重复计算) 复杂数据推导(如列表过滤排序)、减少不必要渲染
useCallback 缓存函数引用(避免函数重新创建) 传递给子组件的回调函数(配合React.memo优化)

关键示例

jsx 复制代码
// useEffect 副作用处理(挂载请求数据,卸载清理定时器)
useEffect(() => {
  // 挂载时请求数据
  const fetchData = async () => {
    const res = await api.getUserList()
    setList(res.data)
  }
  fetchData()
  
  // 挂载时启动定时器
  const timer = setInterval(() => {
    setCount(prev => prev + 1)
  }, 1000)
  
  // 卸载时清理副作用
  return () => {
    clearInterval(timer)
  }
}, []) // 空依赖:仅挂载/卸载执行

// useMemo 缓存计算结果
const filteredList = useMemo(() => {
  return list.filter(item => item.age > 18)
}, [list]) // 仅list变化时重新计算

// useCallback 缓存函数
const handleClick = useCallback(() => {
  setCount(prev => prev + 1)
}, []) // 依赖为空,函数引用不变

3. useEffect 的依赖项及执行规则?常见坑?

核心执行规则

  • 依赖项为空数组 []:仅在组件挂载时执行一次,卸载时执行返回的清理函数;
  • 依赖项为特定值 [a, b]:组件挂载时执行,且a/b变化时重新执行,同时先执行上一次的清理函数;
  • 无依赖项:组件每次渲染后都执行;

常见坑

  1. 遗漏依赖项:如useEffect中使用了state/props但未加入依赖,导致逻辑不生效;
  2. 无限循环:在useEffect中更新state,且state加入依赖,未做条件判断;
  3. 清理副作用不及时:如未清理定时器/事件监听,导致内存泄漏。

4. 自定义 Hooks 的定义及使用场景?

核心答案

  • 定义:以use开头的自定义函数,封装可复用的逻辑,内部可调用内置Hooks;
  • 核心规则:只能在函数组件/自定义Hooks中调用,不能在普通函数/条件语句中调用;
  • 典型场景:请求数据、表单校验、防抖节流、监听窗口大小等。

自定义Hook示例(useRequest.js)

jsx 复制代码
// 封装通用请求逻辑
import { useState, useEffect } from 'react'

export function useRequest(api, params = []) {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  const fetchData = async () => {
    try {
      setLoading(true)
      const res = await api(...params)
      setData(res.data)
    } catch (e) {
      setError(e)
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    fetchData()
  }, params) // 参数变化重新请求

  return { data, loading, error, refetch: fetchData }
}

// 组件中使用
import { useRequest } from '@/hooks/useRequest'
const { data, loading, refetch } = useRequest(api.getUserList, [1, 10])

5. React.memo、useMemo、useCallback 的区别及使用场景?

优化手段 核心作用 适用场景
React.memo 缓存组件,仅props变化时重新渲染 纯展示型子组件,props不频繁变化
useMemo 缓存计算结果,避免重复计算 复杂计算(如列表过滤排序)
useCallback 缓存函数引用,避免函数重新创建 传递给子组件的回调函数(配合React.memo)

优化示例

jsx 复制代码
// 子组件:用React.memo缓存
const Child = React.memo(({ onClick, data }) => {
  return <button onClick={onClick}>{data}</button>
})

// 父组件:用useCallback缓存函数,useMemo缓存数据
const Parent = () => {
  const [count, setCount] = useState(0)
  // 缓存函数,避免每次渲染重新创建
  const handleClick = useCallback(() => {
    console.log('click')
  }, [])
  // 缓存数据,避免每次渲染重新计算
  const data = useMemo(() => `count: ${count}`, [count])

  return <Child onClick={handleClick} data={data} />
}

三、进阶核心(资深级,原理+实战考点)

1. React 虚拟DOM及diff算法原理?

虚拟DOM :用JS对象描述DOM节点的结构和属性(如 { type: 'div', props: { className: 'box' }, children: [] }),避免直接操作真实DOM(DOM操作比JS运算慢100+倍)。

diff算法核心规则(React 18)

  1. 同层比较:只对比同一层级的节点,不跨层级比较(如根节点div不会和子节点p比较);
  2. 类型优先:节点类型不同(如div vs p),直接销毁旧节点、创建新节点;类型相同则对比props;
  3. 列表对比
    • 依赖key唯一标识节点,避免就地复用导致数据错乱;
    • 采用"最长递增子序列"算法,最小化列表节点的移动次数;
  4. React 18优化:支持并发渲染,diff过程可中断,优先处理高优先级任务(如用户输入)。

关键考点:列表渲染为什么必须加key?

  • 不加key:React会"就地复用"节点(列表排序/过滤后,仅更新内容不移动DOM),导致表单值错乱、动画异常;
  • 禁止用index做key:列表顺序变化时index也会变,失去唯一标识作用,推荐用后端返回的唯一ID。

2. React 18 的核心新特性?

核心答案

  • 并发渲染(Concurrent Rendering):渲染过程可中断、恢复,优先处理高优先级任务(如用户输入、动画),提升交互流畅度;
  • 自动批处理(Automatic Batching):将多个state更新合并为一次渲染,减少渲染次数(如Promise/定时器中的setState也会批处理);
  • useTransition:标记低优先级更新(如列表筛选),避免阻塞高优先级操作(如输入框输入);
  • Suspense:支持数据请求 Suspense(配合React Query/SWR),实现"加载中"占位,简化异步渲染逻辑;
  • createRoot:替代ReactDOM.render,启用React 18新特性。

useTransition示例

jsx 复制代码
import { useState, useTransition } from 'react'

const Search = () => {
  const [input, setInput] = useState('')
  const [list, setList] = useState([])
  const [isPending, startTransition] = useTransition()

  const handleInput = (e) => {
    // 高优先级:立即更新输入框
    setInput(e.target.value)
    // 低优先级:标记为过渡更新,不阻塞输入
    startTransition(() => {
      // 模拟复杂列表筛选
      const filteredList = bigList.filter(item => item.includes(e.target.value))
      setList(filteredList)
    })
  }

  return (
    <div>
      <input value={input} onChange={handleInput} />
      {isPending && <div>加载中...</div>}
      <ul>{list.map(item => <li key={item}>{item}</li>)}</ul>
    </div>
  )
}

3. React 状态管理方案对比(useState/useReducer/Redux/Zustand/Jotai)

方案 核心特点 适用场景
useState 轻量,管理组件内部简单状态 单个组件/小型组件状态
useReducer 基于Redux思想,管理复杂状态逻辑 组件内部复杂状态(如多状态联动)
Redux 全局状态,中间件丰富(Thunk/Saga) 大型应用,需严格状态规范
Zustand 轻量全局状态,无Provider嵌套 中小型应用,追求简洁
Jotai 原子化状态,细粒度更新 需精准控制渲染的场景

Zustand示例(轻量全局状态)

jsx 复制代码
// store.js
import { create } from 'zustand'

const useUserStore = create((set) => ({
  name: '张三',
  age: 20,
  updateName: (newName) => set({ name: newName }),
  incrementAge: () => set((state) => ({ age: state.age + 1 }))
}))

// 组件中使用
const User = () => {
  const { name, age, updateName } = useUserStore()
  return (
    <div>
      <p>{name}({age}岁)</p>
      <button onClick={() => updateName('李四')}>修改姓名</button>
    </div>
  )
}

4. React 性能优化的核心手段?

(1)渲染优化
  • 避免不必要的渲染:
    • 用React.memo缓存纯组件;
    • 用useCallback缓存传递给子组件的函数;
    • 用useMemo缓存复杂计算结果;
  • 拆分组件:将大组件拆分为小型纯组件,减少渲染范围;
  • 懒加载组件:React.lazy + Suspense 按需加载组件。
(2)数据优化
  • 列表虚拟滚动:用react-window/react-virtualized渲染长列表,只渲染可视区域;
  • 防抖节流:搜索框输入防抖、滚动/resize事件节流;
  • 缓存请求数据:用SWR/React Query缓存接口数据,避免重复请求。
(3)打包优化
  • 代码分割:React.lazy 拆分代码包,减少首屏加载体积;
  • Tree Shaking:移除未使用的代码(需ES模块);
  • CDN引入第三方库:如React、ReactDOM通过CDN引入,减少打包体积。
(4)运行时优化
  • 减少DOM操作:用React状态驱动视图,避免手动操作DOM;
  • 清理副作用:useEffect中及时清理定时器/事件监听,避免内存泄漏;
  • 避免在渲染中创建函数/对象:如<Child onClick={() => {}} /> 会导致子组件每次重新渲染。

5. React 项目如何处理跨域?

和Vue跨域方案一致,核心分两类:

(1)开发环境(本地调试)
  • 配置代理(Create React App示例):

    jsx 复制代码
    // src/setupProxy.js
    const { createProxyMiddleware } = require('http-proxy-middleware')
    module.exports = function(app) {
      app.use(
        '/api',
        createProxyMiddleware({
          target: 'http://localhost:3000', // 后端接口地址
          changeOrigin: true,
          pathRewrite: { '^/api': '' } // 去掉/api前缀
        })
      )
    }
(2)生产环境
  • 后端配置CORS:设置Access-Control-Allow-Origin为前端域名;
  • Nginx反向代理:将前端请求转发到后端,避免跨域。

四、手写题(高频压轴)

1. 实现自定义 Hook useDebounce(防抖)

jsx 复制代码
import { useState, useEffect } from 'react'

// 防抖Hook:延迟执行函数,避免频繁触发
export function useDebounce(value, delay = 300) {
  const [debouncedValue, setDebouncedValue] = useState(value)

  useEffect(() => {
    // 设置定时器,延迟更新
    const timer = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    // 每次value变化时,清除上一次的定时器
    return () => clearTimeout(timer)
  }, [value, delay])

  return debouncedValue
}

// 组件中使用
const Search = () => {
  const [input, setInput] = useState('')
  // 防抖后的输入值
  const debouncedInput = useDebounce(input, 500)

  // 防抖后请求接口
  useEffect(() => {
    if (debouncedInput) {
      api.search(debouncedInput).then(res => {
        setList(res.data)
      })
    }
  }, [debouncedInput])

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

2. 实现简易版 useState Hook

jsx 复制代码
// 模拟React的useState实现(简化版)
let state = [] // 存储状态
let index = 0  // 标记当前Hook的索引

function useState(initialValue) {
  const currentIndex = index // 保存当前索引
  // 初始化状态
  state[currentIndex] = state[currentIndex] || initialValue

  // 更新状态函数
  const setState = (newValue) => {
    // 支持函数式更新
    if (typeof newValue === 'function') {
      state[currentIndex] = newValue(state[currentIndex])
    } else {
      state[currentIndex] = newValue
    }
    // 模拟重新渲染(实际React会触发组件重渲染)
    render()
  }

  index++ // 索引递增,保证多个useState顺序一致
  return [state[currentIndex], setState]
}

// 模拟渲染函数
function render() {
  index = 0 // 每次渲染重置索引
  // 实际React会重新执行组件函数
  console.log('组件重新渲染,当前state:', state)
}

// 测试
const [count, setCount] = useState(0)
setCount(1) // 输出:组件重新渲染,当前state: [1]
setCount(prev => prev + 1) // 输出:组件重新渲染,当前state: [2]

总结

核心考点回顾

  1. 基础层:React核心特性、JSX原理、props/state区别、组件定义方式;
  2. Hooks层:useState/useEffect规则、自定义Hooks、性能优化(React.memo/useMemo/useCallback);
  3. 进阶层:虚拟DOM/diff算法、React 18新特性、状态管理方案、性能优化;
  4. 实战层:跨域处理、组件懒加载、自定义Hook封装、手写核心逻辑。

答题技巧

  • 基础题:先答核心定义,再补示例/使用场景;
  • Hooks题:结合"副作用""缓存""复用"三个关键词展开;
  • 原理题:用"通俗语言+简化代码"解释(如虚拟DOM="JS对象描述DOM");
  • 项目题:围绕"性能、复用、可维护"展开,体现实战经验。
相关推荐
鹏多多.2 小时前
Flutter使用screenshot进行截屏和截长图以及分享保存的全流程指南
android·前端·flutter·ios·前端框架
LawrenceLan2 小时前
37.Flutter 零基础入门(三十七):SnackBar 与提示信息 —— 页面反馈与用户交互必学
开发语言·前端·flutter·dart
迪巴拉15252 小时前
基于Vue与Spring Boot+Open Cv的智慧校园考勤系统
前端·vue.js·spring boot
swipe2 小时前
JavaScript 对象与属性描述符:从原理到实战
前端·javascript·面试
&活在当下&2 小时前
Vue3 h函数用法详解
前端·javascript·vue.js
小贵子的博客2 小时前
(vue3错误处理)has naming conflicts with other components, ignored.
前端·javascript·vue.js
木斯佳3 小时前
前端八股文面经大全:字节跳动音视频前端一面·下(2026-03-03)·面经深度解析
前端·音视频·状态模式