React项目中为什么推荐用Day.js或date-fns替代Moment.js?

来源:PHP教程作者:樱由罗头衔:网络博主
导读:本期聚焦于樱由罗创作的《React项目中为什么推荐用Day.js或date-fns替代Moment.js?》,敬请观看详情。Moment.js曾经是前端处理日期时间的标配库,但它已进入维护模式,官方也建议开发者迁移到其他方案。在React项目中,Day.js和date-fns是目前最受关注的两个替代品。Day.js只有2KB左右体积,API设计与Moment.js几乎一致,迁移成本极低;date-fns采用函数式设计,支持按需引入和Tree Shaking,配合React Hooks使用非常自然。本文将从包体积、API风格、不可变性、Tree Shaking支持等维度对比这三个库,给出具体的迁移示例代码,包括格式化日期、相对时间计算、时区处理等常见场景,帮助你根据项目实际情况选择最合适的日期库,并顺利完成从Moment.js的迁移。

Moment.js在前端圈火了将近十年,几乎是日期处理的代名词。但它的维护团队已经在官方文档中明确宣布进入维护模式,不再开发新功能,并建议新项目不要再用它。对于React项目来说,这确实是个需要认真对待的问题:一个6KB起步(gzip后约70KB的功能集)的库,加上可变的对象设计和不支持Tree Shaking的模块结构,在现代打包工具下显得越来越不合时宜。替代方案里呼声最高的就是Day.js和date-fns,这篇文章就来聊聊这两个库各自的特点,以及怎么从Moment.js平滑迁移过去。

React项目中为什么推荐用Day.js或date-fns替代Moment.js?

为什么Moment.js逐渐被弃用

首先要理解Moment.js被抛弃的原因,才能明白替代方案解决了什么问题。第一点是体积。Moment.js的完整包gzip后大约有70KB,在追求首屏加载速度的今天,这个体积对于“只是格式化一个日期”的需求来说太重了。虽然可以通过locale定制减小体积,但操作繁琐,效果有限。

第二点是不可变性。Moment的对象是可变的,调用moment().add(1, 'day')会直接修改原对象。这在React里尤其危险,因为React依赖引用比较来判断是否需要重渲染。如果你把moment对象存在state里,然后调用方法修改它,引用没变,组件不会重渲染,界面就会出现数据变了但视图不更新的诡异bug。

第三点是模块化设计。Moment.js是整体加载的,即使你只用了一个format方法,打包时也会把整个库都打进去,Tree Shaking对它基本无效。官方文档对此的解释很坦率:这是历史遗留的架构问题,无法在现有版本上修复。

Day.js:迁移成本最低的选择

如果你的项目里已经有大量Moment.js代码,Day.js几乎是为你量身定做的。它的API设计刻意保持了与Moment.js的高度兼容,大部分代码只需要把moment换成dayjs就能继续跑。先看安装:

npm install dayjs

基本用法对比一下就很直观。原来的Moment.js写法:

import moment from 'moment';

const now = moment().format('YYYY-MM-DD HH:mm:ss');
const nextWeek = moment().add(7, 'day').format('YYYY-MM-DD');
const fromNow = moment('2020-01-01').fromNow();

换成Day.js之后:

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';

// 插件需要手动注册,这是与Moment最大的差异
dayjs.extend(relativeTime);

const now = dayjs().format('YYYY-MM-DD HH:mm:ss');
const nextWeek = dayjs().add(7, 'day').format('YYYY-MM-DD');
const fromNow = dayjs('2020-01-01').fromNow(); // 几年前

注意插件机制这一差异。Moment.js把所有功能都内置了,而Day.js把相对时间、时区、日历、季度等功能拆成了插件,用哪个引入哪个。这个设计正是它能把体积控制在2KB的核心原因。常用的插件有这些:

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(isSameOrBefore);

// 时区转换示例
const time = dayjs('2024-06-01 12:00').tz('Asia/Shanghai').format();
const nyTime = dayjs(time).tz('America/New_York').format('YYYY-MM-DD HH:mm');

中文语言包也是按需加载的,只会在最终产物里增加约2KB,而不是Moment那样动辄几十KB:

import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
dayjs().format('dddd'); // 星期六

另外重要的一点是,Day.js的对象是不可变的。dayjs().add(1, 'day')返回新实例,不会修改原对象,这正好契合React的数据流理念,存在state或props里都很安全。

date-fns:函数式风格与Hooks的天然搭配

如果你更看重Tree Shaking的极致效果,或者喜欢函数式的代码风格,date-fns值得认真考虑。它和Moment的API完全不同:没有日期对象的概念,所有函数都接收Date对象或时间戳作为参数,返回新值。

npm install date-fns

基本用法是这样的:

import { format, addDays, formatDistanceToNow, differenceInDays } from 'date-fns';
import { zhCN } from 'date-fns/locale';

const now = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
const nextWeek = format(addDays(new Date(), 7), 'yyyy-MM-dd');
const diff = differenceInDays(new Date(), new Date('2024-01-01'));
const fromNow = formatDistanceToNow(new Date('2024-01-01'), { locale: zhCN });

注意格式占位符的区别:Moment和Day.js用大写的YYYY-MM-DD,date-fns v2以后用小写的yyyy-MM-dd,迁移时这是最容易踩的坑,大小写写错不会报错,只是输出结果不对,比如大写MM在小写位置的语义完全不同。

date-fns在React Hooks场景下用起来非常顺手。配合useMemo可以精确控制计算时机:

import { useMemo } from 'react';
import { formatDistanceToNowStrict } from 'date-fns';
import { zhCN } from 'date-fns/locale';

function TimeAgo({ timestamp }) {
  const text = useMemo(
    () => formatDistanceToNowStrict(new Date(timestamp), { locale: zhCN, addSuffix: true }),
    [timestamp]
  );
  return <span>{text}</span>;
}

Tree Shaking在这里发挥到极致:打包工具只会把你import进来的函数打进产物,单个函数平均只有几百字节。如果你的项目只在两三个地方用到日期格式化,date-fns可能是体积最优解。

三者对比与选型建议

把关键维度整理成表格方便对比:

维度Moment.jsDay.jsdate-fns
gzip体积约70KB约2KB按需,通常几KB
API风格链式对象链式对象纯函数
不可变性可变对象不可变不可变
Tree Shaking不支持支持(插件级)完美支持
时区支持内置插件v2集成Temporal或第三方
迁移成本极低中高

选型建议很简单:存量项目里Moment代码多、时间紧,选Day.js,配合官方提供的迁移指南,全局替换加上插件注册基本一个下午就能搞定。新项目、团队偏好函数式风格、对包体积锱铢必较,选date-fns。需要重度时区运算的业务(比如跨国会议排期),Day.js加上utc和timezone插件是三者中体验最完整的。

最后补充一点迁移的实操经验:可以先用momentdayjs在同一组件里共存的方式渐进迁移,每替换一个文件就删掉对应的moment引用,等引用数为零后再从package.json里移除依赖。date-fns迁移则建议按功能逐个改写,重点检查所有格式化字符串的大小写。无论选哪个,都不要再给新项目引入Moment.js了,这已经是前端社区的共识。

Day.jsReact日期处理date-fns修改时间:2026-09-15 20:16:37

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260915/57483.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。