React+Antd项目刷新后恢复Datepicker值报date.locale错误
问题描述
使用React + Antd开发项目时,选择Antd DatePicker的日期能正常更新SessionStorage,但页面刷新后,其他表单域能从SessionStorage恢复数据,唯独DatePicker抛出错误:
date.locale is not a function at Object.format (dayjs.js:185:19)
错误截图
SessionStorage中的日期值
父组件 Navigation.tsx
import HotelAndDate from "./HotelAndDate"; import { Steps, message, Form } from 'antd' import Button from 'antd/es/button'; import RoomDetails from "./RoomDetails"; import Payment from "./Payment"; import './index.css' import { useNavigation } from "./useNavigation"; import { useEffect, useState } from "react"; import { useSessionStorage } from "./useSessionStorage"; import * as dayjs from 'dayjs' dayjs().format() export type FormT = { hotel_name: string startDate: string endDate: string parents: number children: number } const initialData: FormT = JSON.parse(sessionStorage.getItem('formData') || '{}') || { hotel_name: '', startDate: '2022-12-22', endDate: '', parents: 0, children: 0 }; function Navigation() { const [data, setData] = useSessionStorage<FormT[] | FormT>('formData', initialData); const [form] = Form.useForm(); useEffect(() => { let storedData = JSON.parse(sessionStorage.getItem('formData') || '{}'); setData(storedData); }, []); console.log('SSS', data); const onFinish = async () => { const values = await form.validateFields(); console.log(values); } var INITIAL_STEPS = [ { title: 'Hotel And Date', content: <HotelAndDate data={data} setData={setData} updateFields={updateForm} />, }, { title: 'Room Details', content: <RoomDetails />, }, { title: 'Payment', content: <Payment />, }, ]; const { current, step, steps, next, prev, goTo, isFirstStep, isLastStep } = useNavigation(INITIAL_STEPS) const items = steps.map((item) => ({ key: item.title, title: item.title })); function updateForm(fields: Partial<FormT>): void { setData(prev => { return { ...prev, ...fields } }) } function handlePreviousClick() { prev(); } return ( <div className=" mx-auto flex max-w-7xl p-6 lg:px-8" style={{ flexDirection: 'column', rowGap: '2rem' }}> <Steps current={current} items={items} labelPlacement='vertical'></Steps> <Form layout="vertical" initialValues={initialData} onFinish={onFinish} > {steps[current].content} </Form> <div className="flex items-center justify-between"> {!isFirstStep && ( <Button type="primary" htmlType="button" onClick={handlePreviousClick}> Previous</Button> )} {current < steps.length - 1 && ( <Button type="primary" htmlType="button" onClick={next}>Next</Button> )} {isLastStep && ( <Button type="primary" htmlType="submit" onClick={() => message.success('Processing complete!')}> Done </Button> )} </div> </div> ) } export default Navigation
子组件 HotelAndDate.tsx(问题出现位置)
function HotelAndDate({ data, setData, updateFields }: { data: any, setData: any, updateFields: any }) { const { hotelListLoading, hotels } = useGetHotelList(); return ( <Row gutter={[32, 32]} justify="space-between"> {/* other form areas */} <Col > <Form.Item name="startDate" label="Start Date" rules={[{ required: true }]}> <DatePicker value={dayjs("")} onChange={(date,dateString) => date && updateFields({ startDate: dateString})} placeholder="Start Date" /> </Form.Item> </Col> {/* other form areas */} </Row> ) } export default HotelAndDate;
解决方案
这个错误的核心原因是:Antd的DatePicker期望接收dayjs实例对象,但从SessionStorage读取的是字符串格式的日期,直接传给DatePicker会导致内部调用dayjs方法时出错。
1. 初始化表单时转换日期字符串为dayjs实例
修改父组件中initialData的初始化逻辑,把从SessionStorage读取的日期字符串转换成dayjs实例:
const storedRaw = sessionStorage.getItem('formData') || '{}'; const storedData = JSON.parse(storedRaw); const initialData: FormT = { hotel_name: '', startDate: '2022-12-22', endDate: '', parents: 0, children: 0, ...storedData, // 转换日期字符串为dayjs实例 startDate: storedData.startDate ? dayjs(storedData.startDate) : dayjs('2022-12-22'), endDate: storedData.endDate ? dayjs(storedData.endDate) : dayjs('') };
2. 修正DatePicker的value绑定
子组件里的DatePicker不要硬写固定值,应该从父组件传递的data中取对应值,同时确保是dayjs实例:
// HotelAndDate.tsx <Form.Item name="startDate" label="Start Date" rules={[{ required: true }]}> <DatePicker value={data.startDate ? dayjs(data.startDate) : dayjs('')} onChange={(date, dateString) => date && updateFields({ startDate: dateString })} placeholder="Start Date" /> </Form.Item>
3. 优化冗余逻辑
父组件中的useEffect属于冗余逻辑,因为useSessionStorage本身已经处理了从SessionStorage读取初始值的逻辑,可以直接删除该useEffect,避免重复设置数据。
内容的提问来源于stack exchange,提问作者barisdevjs
相关产品推荐
相关产品推荐

