一位写了8年React的开发者,把那些年掉过的坑、踩过的雷,整理成了一本不到200页的小册子。他列出的教训清单,读起来像一份"React幸存者口述史"。

一、状态管理:别急着上重武器

打开网易新闻 查看精彩图片

作者开篇就吐槽了一个行业怪象:新手项目刚搭好脚手架,第一件事就是装Redux。

「我见过太多人,包括我自己,在根本不需要的时候引入Redux。」他在书里写道。

他的建议是:先用useState和useReducer(内置的Reducer钩子)撑到极限。什么时候该升级?当你发现props drilling(属性逐层传递)超过三层,或者组件树里到处散落着同步逻辑时。

一个具体判断标准:如果你的状态变更逻辑能写在一个函数里讲清楚,useReducer就够了。如果涉及跨组件、跨路由、甚至跨窗口的状态共享,再考虑Context API或者外部库。

作者特别提到Zustand——一个体积只有1KB的状态管理库。不是因为它技术多先进,而是「API设计得让人不想骂街」。相比之下,Redux Toolkit虽然简化了样板代码,但「你还是得理解一堆概念:slice、thunk、extraReducers」。

二、性能优化:先找到真凶再动手

React开发者最容易犯的错,作者认为是「优化强迫症」。

他列了一组数据:某次咨询中,团队给每个组件都包了React.memo(记忆化组件),结果首屏渲染时间从1.2秒涨到2.8秒。为什么?比较props的成本超过了重渲染本身。

他的排查流程很朴素:

第一步,打开React DevTools的Profiler(性能分析器),录一段用户操作。看火焰图里哪些组件在「闪烁」——这是React标记的意外重渲染。

第二步,别急着上memo。先检查是不是状态放错了位置:一个高频更新的状态,如果放在顶层组件,会拖垮整棵树。

第三步,确认真有性能问题再优化。他的经验值:组件渲染超过16ms(一帧的预算)且发生在用户交互关键路径上,才值得动手。

关于useMemo(记忆化计算)和useCallback(记忆化回调),他的态度更激进:「默认不用,除非Profiler告诉你需要」。这两个钩子本身有开销,而且「会让代码读起来像在做数学题」。

三、副作用处理:useEffect的五个陷阱

作者把useEffect(副作用钩子)称为「React里最容易写错的API,没有之一」。他总结了五个高频踩坑点:

陷阱一:依赖数组撒谎。eslint-plugin-react-hooks(官方推荐的ESLint插件)会提示你补全依赖,但「别闭着眼睛点自动修复」。有时候你故意不想监听某个变化,需要想清楚是真的不需要,还是逻辑设计有问题。

陷阱二:清理函数忘记写。订阅、定时器、WebSocket连接,这些必须在组件卸载时断开。作者的建议:每写一个useEffect,先写return语句,哪怕暂时是空函数。

陷阱三:竞态条件。快速切换路由时,旧的异步请求可能后返回,覆盖新数据。他的解决方案:用AbortController(浏览器原生的请求取消API)或者一个布尔标记位来丢弃过期响应。

陷阱四:无限循环。setState触发重渲染,重渲染又触发setState。检查点:依赖数组里有没有对象或函数引用——每次渲染都是新引用,会打破相等性判断。

陷阱五:把useEffect当生命周期用。React团队反复强调「没有生命周期了」,但很多人还在模拟componentDidMount(挂载后)。作者的建议:重新组织思维模型,从「什么时候运行」转向「什么状态变化需要响应」。

四、组件设计:组合优于配置

作者花了一整章讲「props爆炸」——那种有20个可选参数的组件。

他举了个例子:一个Button组件,size、variant、color、disabled、loading、onClick、startIcon、endIcon……「最后你会发现,任何新需求都靠加参数解决,组件变成瑞士军刀,但每把刀都不好用。」

他的替代方案是复合组件模式(Compound Components)。不是给Button加startIcon参数,而是提供Button.Icon子组件,让调用方自己组装。

代码量可能多一点,但「灵活性是结构性的,不是参数堆出来的」。他引用了React官方文档的说法:「组件之间最自然的协作方式,是像乐高一样拼接,而不是传一堆配置对象。」

另一个反模式是「上帝组件」——一个文件里塞了800行,同时管数据获取、UI渲染、业务逻辑。作者的分割原则:当一段代码需要注释来说明「这部分在做X」时,就该拆成独立组件或自定义钩子。

五、类型安全:TypeScript不是万能药

作者2019年迁移到TypeScript(微软开发的JavaScript超集,带静态类型),但书里有整整一节叫「我后悔的事」。

最大教训:不要为了类型而类型。他见过any(任意类型)泛滥的代码库,也见过为了绕过类型检查写的一堆as unknown as X(双重类型断言)。「这两种情况,还不如不写TypeScript。」

他的实用策略:

严格模式必须开。tsconfig.json里的strict: true,「这是底线,不是可选项」。宽松模式省下的时间,会在调试时加倍偿还。

优先推导,少写显式类型。TypeScript的类型推导能力很强,「let name: string = 'foo'是废话,写成let name = 'foo'就行」。只在函数参数和返回值这种推导边界写类型。

警惕第三方类型定义。@types开头的包可能过时,或者和实际运行行为不一致。他的习惯:遇到可疑的类型错误,先去源码里确认,而不是加@ts-ignore(忽略类型检查)了事。

六、测试策略:别测实现细节

作者维护过测试覆盖率90%但重构就崩的代码库。问题出在测试写了太多「组件内部状态是X」的断言。

他的测试哲学:从用户视角出发,测「用户能看到什么、能做什么」。具体工具推荐React Testing Library,「它强制你查询DOM,而不是组件实例」。

一个反例:测试点击按钮后state.counter等于1。为什么错?用户不在乎state叫什么,只在乎屏幕上是不是显示了1。而且state重构后测试必挂,但功能可能完全正常。

他建议的测试金字塔:大量单元测试(纯函数、工具库)+ 适量集成测试(组件交互)+ 少量端到端测试(关键用户流程)。「别颠倒过来,E2E(端到端测试)太慢了,跑一遍够喝两杯咖啡。」

七、生态选择:谨慎追新

React生态的 churn rate(技术更替率)是作者最头疼的事。他列了一张「血泪清单」:

2016年用Redux + Redux Thunk,2017年换Redux Saga,2018年试GraphQL + Apollo,2019年迁到React Query,2021年又加了Zustand做客户端状态。「每次迁移都是生产力黑洞,而且经常是为了解决上一个方案制造的问题。」

他的决策框架:新技术出现12个月后再评估。看三个信号:GitHub issue的响应速度、是否有公司在生产环境用、核心维护者的投入程度。

对于Server Components(服务端组件)这种React官方主推的新特性,他的态度更保守:「等Next.js(React框架)的App Router稳定了再说,现在文档都在改」。但他承认方向是对的——「把数据获取推到服务端,能减少客户端JS体积,这对移动端很重要。」

八、代码组织:按功能切片,别按技术角色

作者反对经典的MVC(模型-视图-控制器)文件夹结构:components、utils、hooks、contexts各一个文件夹。

「这种结构在代码量少时很清爽,但项目大了之后,改一个功能要开七八个文件夹。」

他推崇的是Feature-Based(基于功能)组织:每个功能一个文件夹,里面包含该功能需要的所有代码——组件、钩子、工具函数、类型定义、测试文件。

一个具体例子:src/features/user-profile/下面有ProfileCard.tsx、useUser.ts、user.types.ts、user.test.ts。「打开这个文件夹,你就拥有了理解这个功能所需的全部上下文。」

共享代码怎么办?src/shared/放真正通用的东西,但「准入门槛要高,不是两个功能用到就该放进来」。他的经验:shared里的代码如果超过50行,大概率放错了地方。

九、调试心法:先复现,再定位

作者花了 surprisingly(意外地)多篇幅讲调试技巧。核心观点:React的报错信息经常指错方向。

他常用的三板斧:

第一,最小复现。把问题组件复制到CodeSandbox(在线代码编辑器)或StackBlitz,逐步删除代码直到bug消失。「最后删掉的那行,就是真凶。」

第二,React DevTools的Components面板。可以看props和hooks的实时值,「比console.log(控制台打印)干净,不会污染代码」。他特别提醒:注意看hooks的调用顺序,违反规则时这里会标红。

第三,断点调试。Chrome DevSources里直接打断点,「比console.log更能看清执行时序」。一个技巧:在useEffect里写debugger;,可以精确停在副作用执行时。

对于那种「本地正常,线上崩」的神秘bug,他的排查清单:环境变量、构建缓存、服务端渲染水合(hydration)不匹配、第三方CDN资源加载失败。

十、持续学习:官方文档是第一优先级

书的最后一章,作者列了他的信息源优先级:

第一梯队:React官方文档、React RFC(Request for Comments,设计提案)、核心团队成员的Twitter/X账号。「官方文档2023年重写后质量很高,beta.react.dev那版比旧版强太多。」

第二梯队:维护良好的社区资源,如React Patterns、Kent C. Dodds的博客。「但要交叉验证,有些文章是三年前写的,API已经变了。」

第三梯队:Medium、Dev.to上的教程。「标题带'终极指南'的,我基本跳过。」

他的学习节奏:每周花30分钟扫一遍React GitHub仓库的更新,看哪些PR(Pull Request,代码合并请求)被合并了。「不用看懂每一行,主要是感知方向。」

最后他承认,写这本书的部分动机是自我整理。「教别人是最好的学习,尤其是当你被迫把模糊经验写成明确规则时。」

如果你正在用React做生产项目,这份清单可以当检查表用——不是每一项都要照做,但至少知道坑在哪里。作者的原话:「我掉进去过,你可以绕着走。」