React组件中new Date()引发无限重渲染,转字符串正常的原因解析
React Formik日期字段无限重渲染问题解析
问题背景
用户提供的React组件代码如下:
import { useFormik } from 'formik'; import React from 'react'; const MyForm = () => { const initialValues = { date: new Date().toISOString().slice(0, 10), // 获取YYYY-MM-DD格式的当前日期 // 其他表单字段... }; const onSubmit = (values) => { // 处理表单提交 console.log(values); }; const formik = useFormik({ initialValues, onSubmit, }); return ( <form onSubmit={formik.handleSubmit}> <div> <label htmlFor="date">Date:</label> <input type="date" id="date" name="date" onChange={formik.handleChange} value={formik.values.date} /> </div> {/* 其他表单字段... */} <button type="submit">Submit</button> </form> ); }; export default MyForm;
疑问
为何当将date设为new Date()时,组件会发生无限重渲染;而设为new Date().toISOString().slice(0, 10)时却能正常工作?背后的原因是什么?
核心原因
new Date()是引用类型:每次组件渲染时,new Date()都会生成一个全新的Date对象。Formik内部会对传入的initialValues做浅比较,发现每次的date都是不同的对象引用,就会判定表单状态需要更新,触发表单逻辑重新计算,进而导致组件重渲染。而重渲染又会再次创建新的Date对象,形成无限循环。new Date().toISOString().slice(0, 10)是原始值类型(字符串):这个表达式返回的是YYYY-MM-DD格式的字符串,属于原始值。只要当前日期不变,每次渲染生成的字符串内容完全一致。Formik比较时会认为initialValues没有变化,不会触发不必要的状态更新,组件也就不会出现无限重渲染的问题。
哪怕日期发生变化,字符串的比较是值比较,只有内容真的改变时才会触发更新,不会像Date对象那样因为每次都是新引用而被误判为状态变化。
内容的提问来源于stack exchange,提问作者Abdelrahman
相关产品推荐
相关产品推荐

