Momentjs对象可变性导致DatePicker异常(React+Antd)

今天在使用受控模式的RangePicker时遇到的bug

以下是两段完全一样的代码,唯一区别是前者使用momentjs,后者使用dayjs:

js 复制代码
import { useState } from "react";
import { DatePicker } from "antd";
import moment from "moment";

const { RangePicker } = DatePicker;

export const ControlledRangePicker = () => {
    const [selectedRange, setSelectedRange] = useState([
        moment().subtract(24, "hour"),
        moment(),
    ]);
    const handleRangeChange = (dates) => {
        if (dates) {
            setSelectedRange(dates);
        }
    };
    return (
        <div>
            <RangePicker
                value={selectedRange}
                onChange={handleRangeChange}
                showTime={{
                    format: "HH:mm",
                    hourStep: 1,
                    minuteStep: 15,
                }}
                format="YYYY-MM-DD HH:mm"
            />
        </div>
    );
};


import dayjs from "dayjs";
export const ControlledRangePicker2 = () => {
    const [selectedRange, setSelectedRange] = useState([
        dayjs().subtract(24, "hour"),
        dayjs(),
    ]);
    const handleRangeChange = (dates) => {
        if (dates) {
            setSelectedRange(dates);
        }
    };
    return (
        <div>
            <RangePicker
                value={selectedRange}
                onChange={handleRangeChange}
                showTime={{
                    format: "HH:mm",
                    hourStep: 1,
                    minuteStep: 15,
                }}
                format="YYYY-MM-DD HH:mm"
            />
        </div>
    );
};

会发现前者的日期选择面板一打开 日期就会疯狂增长,控制台重复报错:

js 复制代码
Warning: Maximum update depth exceeded. 
This can happen when a component calls setState inside useEffect,
but useEffect either doesn't have a dependency array, 
or one of the dependencies changes on every render. 

原因是 Moment 对象是可变对象(mutable),而dayjs是 不可变(immutable)的。 可以用以下代码测试:

js 复制代码
// moment可变性
const date1 = moment('2023-10-01');
const date2 = date1; // 这不是复制,而是引用同一个对象
// const date2 = date1.clone(); 正确的方式:创建副本

date1.add(1, 'day'); // 修改date1

console.log(date1.format('YYYY-MM-DD')); // 2023-10-02
console.log(date2.format('YYYY-MM-DD')); // 2023-10-02  date2也被改变了
js 复制代码
// dayjs 不可变性
const date1 = dayjs('2023-10-01');
const date2 = date1; 

const date3 = date1.add(1, 'day'); // 返回新的对象,不改变原对象

console.log(date1.format('YYYY-MM-DD')); // 2023-10-01  原对象不变
console.log(date2.format('YYYY-MM-DD')); // 2023-10-01  
console.log(date3.format('YYYY-MM-DD')); // 2023-10-02  新对象

React的渲染机制期望状态更新是可控的,但Moment.js的 mutable 特性会让状态变得不可预测 。

而且momentjs体积比dayjs大,antd v4到v5 也是从momentjs 变成了 dayjs。

相关推荐
@大迁世界20 小时前
2026年React大洗牌:React Hooks 将迎来重大升级
前端·javascript·react.js·前端框架·ecmascript
吃西瓜的年年1 天前
react(三)action 表单
前端·javascript·react.js
我命由我123451 天前
在 React 项目中,可以执行 npm start 命令,但是,无法执行 npm build 命令
前端·javascript·vue.js·react.js·前端框架·json·ecmascript
卸任1 天前
Electron霸屏功能总结
前端·react.js·electron
TheRouter1 天前
AI Agent 开发中的模型调度策略:何时用便宜模型,何时用强模型
前端·人工智能·react.js
ZHENGZJM1 天前
前端基石:React + Vite + TypeScript 项目搭建
前端·react.js·typescript
ZHENGZJM1 天前
认证增强:图形验证码、邮箱验证与账户安全
安全·react.js·go·gin
光影少年1 天前
RN长列表(FlatList)性能优化的具体手段有哪些?
react native·react.js·性能优化
阿捞21 天前
python-langchain框架(3-20-智能问答ZeroShot_ReAct Agent 从零搭建)
python·react.js·langchain
Lee川2 天前
从零构建现代化登录界面:React + Tailwind CSS 前端工程实践
前端·react.js