Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.0.0 form组件使用initialValues 初始化数据,当包含“date”数据时,DatePicker组件报错“date.clone is not a function” #22185

Closed
1 task done
larants opened this issue Mar 13, 2020 · 10 comments

Comments

@larants
Copy link

larants commented Mar 13, 2020

  • I have searched the issues of this repository and believe that this is not a duplicate.

Reproduction link

https://https://u.ant.design/codesandbox-repro

Steps to reproduce

// 服务端返回数据结构
const current = {
    "id": 1
    "purchased_at": "2020-03-13"
}

<Form form={form} initialValues={current} onFinish={onSubmit}> 
       <Form.Item
            {...formLayout}
            name="purchased_at"
            label="购买时间"
            rules={[{
              required: true,
              message: '请选择购买时间'
            }]}
          >
            <DatePicker />
       </Form.Item>
</Form>

What is expected?

正常渲染

What is actually happening?

程序报错TypeError: date.clone is not a function

Environment Info
antd 4.0.0
React 16.8.6
System Mac
Browser Chrome

我知道是“时间格式”的问题
在V3版本中使用了initialValue来处理这个问题

   <Form.Item {...formItemLayout}>
                    {getFieldDecorator('purchased_at', {
                      rules: [{ required: true, message: '请选择预计下单时间' }],
                      initialValue: current.purchased_at ? moment(current.purchased_at ) : null,
                    })(
                      <DatePicker
                        disabled={infoDisable}
                        showTime
                        placeholder="请选择"
                        format="YYYY-MM-DD"
                      />
                    )}
   </Form.Item>

在V4版本中,我看到了Form.Item 中有normalize 参数,但实际也没有解决啥问题。
请问在不处理服务端返回数据结构的前提下,我该怎么处理?

@afc163
Copy link
Member

afc163 commented Mar 13, 2020

提前处理一下 current 就行了。

@larants
Copy link
Author

larants commented Mar 13, 2020

提前处理一下 current 就行了。

所以除了这个方法之外了没有更好的方案了吗?create和update我是共用一个editForm,日期类型又比较常用,所以我都要判断处理...

@larants
Copy link
Author

larants commented Mar 13, 2020

提前处理一下 current 就行了。

如果这个DatePicker组件能够判断是否为moment类型,如果不是,可以自己处理就完美了!因为服务端返回的基本都是string类型

@afc163
Copy link
Member

afc163 commented Mar 13, 2020

v3 版本在 initialValue 中也是要处理的,v4 不过换了个地方,DatePicker 接收不了 string 类型的 value,都是要处理的。

@afc163 afc163 closed this as completed Mar 13, 2020
@larants
Copy link
Author

larants commented Mar 13, 2020

v3 版本在 initialValue 中也是要处理的,v4 不过换了个地方,DatePicker 接收不了 string 类型的 value,都是要处理的。

嗯,我准备自定义一个组件来处理这个问题。谢谢!
记录一下解决方案!

import React from 'react';
import moment from "moment";
import { DatePicker } from 'antd';

const CustomDatePicker = props => {
  const {value, onChange, ...other} = props;
  const time = value ? moment(value) : null;
  const triggerChange = (_, dateStr) => {
    onChange && onChange(dateStr);
  };

  return (
    <DatePicker
      defaultValue={time}
      onChange={triggerChange}
      {...other}
    />
  )
};

export default CustomDatePicker;

@io-o
Copy link

io-o commented Mar 16, 2020

@larants

你好,小白问下, 异步请求的数据,怎么填充到表单里?

数据是异步拿到的, initialValues这时候不会生效

@larants
Copy link
Author

larants commented Mar 17, 2020

@larants

你好,小白问下, 异步请求的数据,怎么填充到表单里?

数据是异步拿到的, initialValues这时候不会生效

我们都知道react是数据驱动的,所以数据发生变化的时候,表单会重新渲染,我们要做的就是在异步获取数据的时候加一个“过度”,在antd里有提供两个这种“过度”的组件Spin、Skeleton,可以阅读下相关文档

使用demo

const [current, setCurrent] = useState({});
const [spinning, setSpinning] = useState(true);
// 异步处理
 useEffect(() => {
   request().then(r => {
      setCurrent(r.data)
      setSpinning(false);
    })
  }, []);
省略
return( 
<Spin spinning={spinning}>
        <Form form={form} initialValues={current} onFinish={onFinish}>
          <Form.Item>
          ....
          </Form.Item>
       </Form >
</Spin>
);

这个是我的方案(缺点是多次异步的时候,如何判断最后一个返回),如果有更好的,可以再补充

@lynxkor
Copy link

lynxkor commented Apr 17, 2020

const [formVals, setFormVals] = useState({
...props.values,
effectiveOn: props.values.effectiveOn ? moment(props.values.effectiveOn) : null,
expiredOn: props.values.expiredOn ? moment(props.values.expiredOn) : null
});

我的处理方式是这样的,供你参考

@LastStranger
Copy link

@larants

你好,小白问下, 异步请求的数据,怎么填充到表单里?

数据是异步拿到的, initialValues这时候不会生效

我们都知道react是数据驱动的,所以数据发生变化的时候,表单会重新渲染,我们要做的就是在异步获取数据的时候加一个“过度”,在antd里有提供两个这种“过度”的组件Spin、Skeleton,可以阅读下相关文档

使用demo

const [current, setCurrent] = useState({});
const [spinning, setSpinning] = useState(true);
// 异步处理
 useEffect(() => {
   request().then(r => {
      setCurrent(r.data)
      setSpinning(false);
    })
  }, []);
省略
return( 
<Spin spinning={spinning}>
        <Form form={form} initialValues={current} onFinish={onFinish}>
          <Form.Item>
          ....
          </Form.Item>
       </Form >
</Spin>
);

这个是我的方案(缺点是多次异步的时候,如何判断最后一个返回),如果有更好的,可以再补充

没有效果诶,即使在外围加了spin组件,form还是被渲染了,initialValue还是没更新

@longhaiyan
Copy link

@larants

你好,小白问下, 异步请求的数据,怎么填充到表单里?

数据是异步拿到的, initialValues这时候不会生效

可以改为使用 antd 的 ProFrom,它提供了 request api,支持异步设置 initialValues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants