首页技术专题博客目录我的收藏关于与联系

重构老代码的痛:从 jQuery 到 React 的迁移

接手了一个 5 年前的 jQuery 项目,代码乱成一团。花了半年时间,逐步迁移到 React。这篇文章记录一下迁移过程中的痛苦和收获。

接手老项目

刚入职的时候,老板让我接手一个老项目。这个项目用 jQuery 写的,已经运行了 5 年,代码有 2 万多行。

打开代码一看,我傻了。全局变量到处都是,函数名都是 doSomethinghandleClick 这种,根本看不出是干什么的。注释都是中文,还都是"这里改一下"这种。

代码的问题

这个项目的问题太多了:

  • 全局变量到处都是,不知道哪个函数改了哪个变量
  • 事件绑定混乱,一个按钮绑了 3 个 click 事件
  • DOM 操作直接写,没有封装,重复代码很多
  • 没有模块化,所有代码都在一个文件里
  • 没有构建工具,直接写 HTML、CSS、JS

最要命的是,这个项目还在用,不能停。每次改功能,都要小心翼翼,生怕改坏了。

决定重构

用了一个月,我实在受不了了。跟老板说,这个项目得重构,不然以后维护成本太高。

老板问要多久,我说至少半年。老板说行,但功能不能停,要边重构边维护。

迁移策略

我们选了渐进式迁移,不是一次性重写:

  • 新功能用 React 写
  • 老功能逐步迁移,一个模块一个模块来
  • 两个系统共存,用 iframe 或者微前端方案

这样风险小,不会一次性改坏所有功能。

第一个模块:用户登录

选了最简单的模块开始:用户登录。这个模块逻辑简单,改起来风险小。

但改起来才发现,没那么简单。jQuery 的登录逻辑和 React 的登录逻辑不一样:

  • jQuery 直接操作 DOM,React 用状态管理
  • jQuery 的事件处理是命令式的,React 是声明式的
  • jQuery 的 AJAX 用 $.ajax,React 用 fetchaxios

花了 2 周,才把登录模块迁移完。测试了好几遍,确保没问题。

第二个模块:数据列表

登录模块迁移完,开始迁移数据列表。这个模块复杂一些,有分页、搜索、排序。

jQuery 的代码是这样的:

$('#search-btn').click(function() { var keyword = $('#keyword').val(); $.ajax({ url: '/api/search', data: { keyword: keyword }, success: function(data) { $('#result-list').html(''); data.forEach(function(item) { $('#result-list').append('<div>' + item.name + '</div>'); }); } }); });

React 的代码是这样的:

const [keyword, setKeyword] = useState(''); const [results, setResults] = useState([]); const handleSearch = async () => { const response = await fetch(`/api/search?keyword=${keyword}`); const data = await response.json(); setResults(data); }; return ( <div> <input value={keyword} onChange={e => setKeyword(e.target.value)} /> <button onClick={handleSearch}>搜索</button> {results.map(item => <div key={item.id}>{item.name}</div>)} </div> );

看起来 React 的代码更清晰,但迁移起来很麻烦。要理解 jQuery 的逻辑,再转换成 React 的逻辑。

遇到的坑

坑一:全局状态

jQuery 的代码用全局变量存状态,比如 var currentUser = null;。React 要用 Context 或者状态管理库。

我们用了 Context,但发现 Context 更新会导致所有组件重渲染。后来用了 Zustand,才解决了问题。

坑二:事件绑定

jQuery 的事件绑定是动态的,可以随时绑定和解绑。React 的事件绑定是静态的,在组件渲染时确定。

有些复杂的交互,jQuery 用事件委托,React 要重新设计组件结构。

坑三:DOM 操作

jQuery 直接操作 DOM,比如 $('#element').show()。React 用状态控制显示隐藏,比如 {isVisible && <div>...</div>}

有些复杂的 DOM 操作,jQuery 很简单,React 要写很多代码。

迁移进度

迁移了半年,进度如下:

  • 用户登录:完成
  • 数据列表:完成
  • 表单提交:完成
  • 文件上传:完成
  • 图表展示:进行中
  • 复杂交互:还没开始

大概完成了 60%,剩下的都是复杂的模块,迁移起来更麻烦。

迁移的收获

虽然迁移很痛苦,但收获也很多:

  • 理解了老代码的逻辑,虽然很乱,但至少知道了
  • 学会了渐进式迁移,不是所有重构都要一次性完成
  • 提升了 React 技能,写了很多 React 代码
  • 改善了代码质量,新代码比老代码清晰很多

如果重新开始

如果重新迁移一个老项目,我会:

  • 先梳理代码结构,理解业务逻辑
  • 从最简单的模块开始,逐步迁移
  • 做好测试,确保迁移后功能正常
  • 统一代码规范,新代码要清晰

总结

重构老代码是个痛苦的过程,但也是必要的。老代码不重构,维护成本会越来越高。

如果你们项目也有老代码要重构,建议用渐进式迁移,不要一次性重写。风险小,效果好。

另外,重构要有耐心。半年时间看起来很长,但比起以后一直维护老代码,这个时间还是值得的。

评论区