过去几年里,只要聊到 React,话题很快会滑向同一个方向:生态太杂了。路由有 React Router、TanStack Router;状态管理有 Redux、Zustand、MobX、Jotai、Recoil;数据请求有 React Query、SWR;表单有 Formik、React Hook Form;就连定时器、防抖、滚轮监听这种小功能都能找到对应的 hook 库。一个新人走进去,大概率不是被 React 本身难倒,而是被“到底该学哪个库”这件事劝退。
我见过很多前端学习者,花了一周时间把 React 官方文档看完,然后打开招聘 JD 一看,要求 Redux、React Router、React Query、Next.js,马上又陷入新一輪选择焦虑。这其实不是学习能力的问题,而是缺少一张“地图”。热搜词里长期躺着 react 面试题、react 面经、react和vue生命周期差异、react router实战这类词,也说明大家真正关心的不是某一个 API 叫什么,而是整个生态是怎么串起来的。
这篇文章想做的,就是把 React 主流库按照“它们到底在解决什么问题”来重新梳理一遍。不追求 12 分钟讲完所有库,因为这不现实,也没有必要。我更想帮你建立一个判断框架:什么场景该用什么库,单次使用和长期维护要分别考虑什么,面试里聊到这些库时,真正该讲清楚的点是什么。
1. 先想清楚一件事:React 生态到底在解决什么问题
1.1 表面的问题是工具太多,实际的问题是“状态该放哪里”
很多人看 React 生态,第一反应是库太多、选型难。这个感受是真的,但观察还不够深。
把所有主流库拉平来看,你会发现它们服务的其实是一条主线:组件如何描述、数据如何流动、副作用如何处理、跨端如何复用。
- 组件描述:JSX、React Component、Hooks 负责这件事。
- 路由:React Router 告诉应用“当前 URL 对应哪个界面”。
- 状态管理:Redux、Zustand、MobX、Jotai 负责处理“多个组件共享一份数据”。
- 数据请求:React Query、SWR 负责处理“服务端数据在客户端的缓存、加载、更新”。
- 表单:React Hook Form、Formik 负责处理“用户输入的状态和校验”。
- 跨端:React Native 负责把 React 组件跑在 iOS 和 Android 上。
看起来功能各不相同,但如果追问一层,它们都在回答同一个问题:一份数据,在什么时候,应该放到哪个范围里?
是放在组件内部,用useState就够了?还是要提升到父组件,通过 props 往下传?还是要放到组件树之外,做成全局状态?还是要和服务端保持同步,用一个数据请求层来管理?
这个问题的答案,决定了你选什么库、把库放哪一层、什么时候可以不用库。
1.2 一个容易误判的点:不是所有共享数据都要上状态管理库
新手最常见的误解,是把“状态管理库”当成“共享数据的唯一方案”。
实际上,React 本身已经有足够简单的手段:
useState:组件内部状态。useReducer:组件内部复杂状态。Context+useContext:跨组件共享不太频繁变化的数据。props:父传子的单向数据流。
在常见实践里,如果共享数据只在少数几个组件之间传递,而且变化频率不高,用 Context 就够了。很多项目一上来就引入 Redux,结果 redux-devtools 里永远只有一两个 action,大部分状态还是放在组件内部。
判断该不该上状态管理库,可以看三个信号:
- 状态是否被很多无关组件共享。
- 状态更新逻辑是否复杂到值得单独维护。
- 团队是否需要时间旅行调试或持久化中间件。
三个信号都不是强需求时,先不引入全局状态管理库,通常是一个更稳的选择。
先别急着把库里能用的都装上。React 生态的复杂度,不是功能不够,而是“什么时候不该用某个库”这个判断比用库本身难。
1.3 React 真正改变的是思维方式
学 React 和学 Vue 有一个非常直观的差异:Vue 把很多能力内置在框架里,你跟着模板语法走就行;React 则更像一块乐高底板,它只负责最小内核,数据、路由、请求都需要你自己挑零件。
这个设计哲学决定了 React 生态的丰富,也决定了它的学习曲线不是“学会一个框架”,而是“学会一套组合工作流”。
所以,理解 React 主流库,其实是在理解一套组件化设计思路的多种实现方式。一旦想通这条主线,再去看 React Router、Zustand、React Query,就不会觉得它们是一堆零散工具,而是同一套问题的不同切面。
2. 路由与状态管理:为什么 React Router 是事实标准,什么时候不需要全局状态
2.1 React Router 不只是一个“页面跳转工具”
React Router 是 React 生态里生命力最稳定的库之一。从 React Router 5 到 6,API 变化不小,但核心思想没有变:让 URL 成为应用状态的一部分。
React Router 6 以后,推荐写法已经和 5 有了明显差异。常见做法是:
// 声明路由配置 const router = createBrowserRouter([ { path: '/', element: <Home />, }, { path: '/user/:id', element: <UserDetail />, }, ]); <RouterProvider router={router} />这个写法的好处是,路由表变成一份可静态分析的数据结构,不再只是散落在组件里的<Route>标签。
React Router 真正需要理解的概念是这几个:
createBrowserRouter:创建路由实例。RouterProvider:把路由实例注入组件树。loader:进入路由前,先并行加载数据。action:处理表单提交等写操作。useParams、useNavigate、useLocation:在组件里读取当前路由信息。
如果你在 React Router 实战中用过 v5 的<Switch>,再切到 v6 会觉得清爽很多。v6 不再需要手动排序路由,路由匹配规则更接近静态路由表的直觉。
2.2 状态管理:Redux、Zustand、Jotai 到底怎么选
状态管理是 React 生态里讨论最多、也最容易写成长篇对比文档的话题。这里不做纯功能列表,只给一个判断框架。
Redux 适合的场景:
- 团队规模大,需要严格约定数据更新方式。
- 状态更新流程复杂,需要 middleware、持久化、时间旅行调试。
- 项目已经有成熟的 Redux 工具链。
Redux 的问题不是它不好,而是它的心智负担和样板代码偏重。在真实项目里,如果只用一个全局 store 存几个异步请求结果,Redux 的收益其实发挥不出来。
Zustand 适合的场景:
- 想要全局状态,又不想写太多样板代码。
- 希望用 hooks 直接读取 store。
- 项目不大,但需要跨组件共享状态。
Zustand 的写法直观很多:
import { create } from 'zustand'; const useCountStore = create((set) => ({ count: 0, increase: () => set((state) => ({ count: state.count + 1 })), }));Jotai 适合的场景:
- 喜欢原子化状态。
- 状态之间有依赖关系,希望按需组合。
- 不太想有一个大而全的全局 store。
三个库不是对立关系。它们代表的是“状态管理”这个要求的三种粒度:Redux 是中央集权,Zustand 是省去繁文缛节的状态中心,Jotai 是原子粒度。
| 库 | 核心模型 | 适合场景 | 不适合场景 |
|---|---|---|---|
| Redux | 单一 store,reducer 集中更新 | 大型团队、复杂更新链路 | 小项目、快速原型 |
| Zustand | 轻量 store,hooks 读取 | 中大型项目的通用状态 | 需要严格架构约束的团队 |
| Jotai | 原子状态,按需派生 | 状态依赖关系强的场景 | 团队习惯集中式状态管理时 |
2.3 最容易被忽略的选择:不引入状态管理库
一个很容易被忽略的事实是,很多“需要状态管理”的场景,是组件层级设计得太深导致的。
如果一个状态要从最底层子组件传到最顶层,再下传给另一边,三层以上的 props 钻透会让代码变得很难受。这时候,与其立刻引入 Redux,不如先检查一下组件树的层级是否合理、是否可以把共享状态抽到一个中间层组件里、是否真的需要全局可访问。
从工程经验看,正确的顺序通常是:先简化组件结构,再考虑 Context,最后才考虑状态管理库。顺序反了,就会用技术手段掩盖设计问题。
3. 生命周期到 Hooks:React 和 Vue 差异背后的设计逻辑
3.1 React 类组件生命周期容易记混,本质是没抓住两条线
React 面试题里,“生命周期”是高频考点,React 和 Vue 生命周期的差异更是常客。
类组件的生命周期之所以难记,是因为 API 看起来很多:componentDidMount、componentDidUpdate、componentWillUnmount,再加一个getDerivedStateFromProps、shouldComponentUpdate。看一遍能看懂,过两天又忘了。
我建议用一种更朴素的方式记:组件有三个阶段,挂载、更新、卸载。每个阶段 React 都会给你几个可选的“插手时机”。
Hooks 出现后,很多生命周期函数被合并进useEffect的统一模型里。这是 React 设计上的重要转变:它不再要求你把“在什么时候做什么”拆成多个方法,而是要求你用“这个数据变化后需要发生什么”的视角去想。
// 挂载后执行一次 useEffect(() => { console.log('mounted'); return () => { console.log('unmounted'); }; }, []);// count 变化后执行 useEffect(() => { console.log('count changed:', count); }, [count]);这个模型更符合人的直觉。你不需要去背componentDidMount和componentDidUpdate的区别,只需要想清楚一个副作用依赖哪些数据。
3.2 React 和 Vue 生命周期差异,到底差在哪
React 和 Vue 的差异,表面上体现在框架 API 上,实际差异在两个方面。
第一,数据流模型不同。React 要求数据不可变,状态更新后重新渲染;Vue 基于依赖追踪,数据变化时精准更新视图。这导致 React 更新粒度通常更大,Vue 更细,但细也意味着对响应式系统的依赖更复杂。
第二,生命周期切入的痛点不同。Vue 把created、mounted、beforeUnmount等分成清晰的节点,写起来很明确;React 则更偏向函数式、声明式,把“副作用”统一交给 hooks。
面试里如果被问到差异,比较好的回答思路是:先讲数据流模型,再讲生命周期粒度,最后落到代码组织方式上。不要只背生命周期对照表,那样显得没有真正理解框架。
3.3 Hooks 不是新生命周期,而是一种新的组织单元
很多刚学 Hooks 的人有一个困惑:useEffect到底对应哪个生命周期?
这个问题的答案,取决于你怎么写依赖数组。它有弹性,可以模拟挂载、更新、卸载,也可以完全覆盖不了某个生命周期场景。这不是 bug,它是刻意设计。
真正熟练使用 React 的标志,不是把所有类组件生命周期转译成 hooks,而是开始用useEffect的视角组织副作用:先声明数据依赖,再描述副作用,最后考虑清理。这才是 React 想引导你养成的习惯。
4. React Native:一套代码走多端,边界在哪里
4.1 React Native 的定位:它是 React 生态里的“跨端”分支
热搜词里有一组很现实的词:react native 启动白屏、react native 运行在 android studio、react native 统计图。这说明 React Native 的讨论早就过了“它能不能用”的阶段,大家关心的是“落地时怎么处理实际问题”。
React Native 的核心价值不是“写一次,到处运行”,而是“用 React 的组件模型,以接近原生的方式构建移动应用”。它复用了 React 的心智模型,但底层渲染不经过 DOM,而是通过 JavaScript 引擎和原生端通信,把组件映射成原生视图。
4.2 启动白屏:最常见的问题之一,怎么排查
React Native 启动白屏,在老版本和新版本里都可能遇到,原因往往不一样。在常见实践里,排查时可以先按下面的链路走:
- 看原生端日志。白屏最常见原因是 JS bundle 没有加载成功,原生日志会直接告诉你。
- 看 Metro 是否正常运行。开发模式下,如果 Metro 断掉或端口被占用,页面就无法加载 JS bundle。
- 看 JS 层是否有未捕获异常。React Native 中 JS 报错有两种表现,一是红屏(开发模式),一是白屏(release 模式)。
- 看入口 render 是否执行。在根组件里加一个临时日志,确认 JS 是否真的跑起来。
- 看原生依赖是否匹配版本。RN 版本和原生模块版本不匹配,会导致原生层初始化失败。
| 现象 | 优先排查 | 常见原因 |
|---|---|---|
| 白屏 | 原生日志 | JS bundle 加载失败 |
| 白屏但原生日志正常 | JS 层异常 | 渲染入口报错 |
| 白屏只在 release 出现 | bundle 构建 | 资源路径或 bundle 配置错误 |
| 白屏只在模拟器出现 | 网络访问 | Metro 连接问题 |
React Native 出现白屏时,不要急着改代码。先确认 JS bundle 有没有加载成功,再确认原生层是否已经渲染出容器,最后才去查组件问题。排查顺序反了,通常只是在瞎试。
4.3 React Native 统计图怎么选
如果要在 React Native 里做统计图,选择维度和 Web 端不一样。Web 端可以选 ECharts、Chart.js、AntV,但 RN 环境没有 DOM,这些库不能直接用。
常见方向有:
react-native-svg+ 自己画图:适合图表需求固定、不想引入重依赖。react-native-svg-charts:基于 SVG,简单图表够用。victory-native:图表功能完整,但包体积偏大。- 使用 WebView 方案,把图表逻辑放在 Web 里:适合团队 Web 端已经有一套图表组件的情况。
选择建议是:如果项目只缺一两个简单图表,先试react-native-svg-charts;如果图表交互复杂、类型多,可以评估 WebView 方案或 Native 图表库。不要一上来就追求“大而全”,RN 的包体积和原生依赖成本比 Web 端高很多。
4.4 React Native 适合谁、不适合谁
适合的场景:
- 团队已经熟练使用 React,希望复用一部分知识。
- 产品需要同时覆盖 iOS 和 Android,但人力有限。
- 业务中 UI 交互复杂,但原生能力依赖不深。
不适合的场景:
- 需要重度使用原生特性,比如复杂视频处理、底层传感器、高性能游戏。
- 急需极致原生体验,且团队能同时维护两套原生代码。
- 业务单纯是展示型,可以考虑普通 Web 套壳,不一定非要 RN。
React Native 的边界不是“能不能做”,而是“团队愿不愿意处理原生层的问题”。长期使用它,一定绕不开原生配置、版本兼容、构建工具链这些事。
5. 那些 React 面试题,本质在考什么
5.1 热搜里的面试题,逃不出五类问题
react 面试题、react 面经、react和vue生命周期差异、react 省市查询组件完整代码这类词长期排在前列。看起来每道题都不一样,但归纳起来,React 面试其实就在考五类问题。
第一类,组件基础。如何拆分组件、如何传参、受控组件和非受控组件。
第二类,生命周期。类组件生命周期、hooks 替代方案、useEffect 依赖数组行为。
第三类,状态管理。Context、Redux、Zustand,组件间通信方案。
第四类,渲染优化。React.memo、useMemo、useCallback、shouldComponentUpdate,为什么有些优化没用。
第五类,生态应用。React Router 使用、Next.js SSR、React Native 跨端。
一旦你把这五个方向拉成一个知识树,再看那些散落的面经,就不会觉得手忙脚乱。因为你知道每一道题挂在哪棵树上。
5.2 面经是路标,不是标准答案
有些准备面试的人,喜欢把面经题背下来。我不是很推荐。原因很简单,面试官会追问“为什么”,只会背答案撑不过三轮。
更好的方式是:每看到一道小题,就把它放到更大的框架里。比如被问到“React 和 Vue 生命周期差异”,不止要记住对应关系,还要能说明背后的数据流模型差异;被问到“为什么 useEffect 里不能写 async 函数”,要从 cleanup 和竞态处理的角度解释,而不是背结论。
5.3 2026 年面试会盯住什么
如果按技术演进趋势推,React 相关面试接下来会越来越关注几个方向:
- React 19 的并发渲染和过渡 API。
- Server Components 对数据请求层的影响。
- 编译优化,比如 React Compiler。
- 从 Web 到 React Native、到全栈框架的能力延伸。
这类题目不需要你背发布说明,而是看你有没有真实项目体感。平时多留意框架更新日志,别只看教程标题。
6. 沉淀一套 React 库选型判断框架
6.1 先跑通,再优化,最后工程化
无论选什么库,我建议都按“三步走”的顺序来。
第一步,最小可用流程。用最少的库、最少的封装,把功能跑通。不要一开始就引入一堆抽象层。
第二步,小样本验证。在真实项目里抽取一个模块,用候选库实现。观察的不只是代码能不能运行,还包括代码量、团队理解成本、调试难度。
第三步,工程化接入。确认方案可行后,再考虑中间件、持久化、日志、类型、测试、代码规范、团队约定。
这个顺序可以避免两个问题:一是过早抽象,代码还没跑通就开始封装架构;二是过度依赖库,遇到一个小问题就再引一个新库。
6.2 一个小而实用的 React 选型清单
把前面讨论的内容收束成一个清单,供你在新项目里快速判断。
| 问题 | 判断方向 |
|---|---|
| 路由需求是否复杂? | 单页应用直接用 React Router;需要静态路由、嵌套路由、loader 可以考虑 TanStack Router |
| 全局状态是否必要? | 先检查组件分层和 props;确认需要再选 Zustand、Redux 或 Jotai |
| 服务端数据请求多不多? | 若有大量异步状态,直接用 React Query 或 SWR |
| 表单是否复杂? | 表单状态多、校验复杂,用 React Hook Form |
| 需要跨端吗? | 需要原生交互才考虑 React Native;不需要的话用 Web 技术栈更轻 |
| 团队维护能力如何? | 团队小选轻量方案;团队大、需要强约束,选 Redux + 工具链 |
这个清单不是标准答案,而是一组提问。真正做决定的人,还是要结合团队情况。
6.3 长期使用比第一眼惊艳更重要
最后想多说一句。React 生态里每个主流库能成为主流,基本都有它存在的理由。很多初学者喜欢凭第一眼感受做选择:看到 Zustand 短小精悍就决定抛弃 Redux,看到 React Query 太方便就决定不再自己封装请求。
但真实项目里的体验,和第一次 demo 的体验差别很大。一个库能不能长期用,取决于几点:
- 团队里每个人读代码都能理解。
- 出了问题能在社区找到记录。
- 长时间不更新也依然稳定。
- 它解决的问题,在你的业务里确实常见。
这才是选型真正的判断标准。不是“这个库看起来高级”,而是“这个库在一年后,能不能减少我们团队的维护负担”。
回到开头那句话:React 主流库的复杂性,不是要你把每一样都摸透,而是要学会判断“当前项目需要什么、不需要什么”。能想清楚这一层,你就不需要靠背诵面经或跟热门工具清单来支撑自己的技术判断了。