order: 4 group: order: 3 title: 高级用法
toc: false
表单方法(form)
FormRender v1.x 使用了状态内置的模型,所以外部对表单的所有操作都依赖于 form 实例提供的方法。 本篇会 cover 以下这些常用 api:
form.submit
form.setValues
form.setValueByPath
form.setSchemaByPath
以及以下的生命周期
beforeFinish
onFinish
我们写一个最常用的场景:加载一个已经填写完成的表单,从服务端异步获取数据(这里使用 mock);修改表单并提交新数据给服务端
例 1: 表单与服务端的基本交互
异步加载表单 Schema, 服务端数据填充表单初始值, 提交校验通过后提交数据给服务端
/**
* transform: true
* defaultShowCode: true
*/
import React, { useState, useEffect } from 'react';
import { Button, Space, message } from 'antd';
import FormRender, { useForm } from 'form-render';
import { fakeApi, delay } from './utils';
const Demo = () => {
const form = useForm();
const [schema, setSchema] = useState({});
const getRemoteData = () => {
fakeApi('xxx/getForm').then(_ => {
form.setValues({ input1: 'hello world', select1: 'c' });
});
};
useEffect(() => {
// 异步加载表单
delay(1000).then(_ => {
setSchema({
type: 'object',
properties: {
input1: {
title: '简单输入框',
type: 'string',
required: true,
},
select1: {
title: '单选',
type: 'string',
enum: ['a', 'b', 'c'],
enumNames: ['早', '中', '晚'],
},
},
});
});
}, []);
const onFinish = (data, errors) => {
if (errors.length > 0) {
message.error(
'校验未通过:' + JSON.stringify(errors.map(item => item.name))
);
} else {
fakeApi('xxx/submit', data).then(_ => message.success('提交成功!'));
}
};
return (
<div style={{ width: '400px' }}>
<FormRender form={form} schema={schema} onFinish={onFinish} />
<Space>
<Button onClick={getRemoteData}>加载服务端数据</Button>
<Button type="primary" onClick={form.submit}>
提交(见console)
</Button>
</Space>
</div>
);
};
export default Demo;
例 2:服务端校验
服务端校验,通过 beforeFinish
从外部回填 error 信息到表单,注意 beforeFinish
需返回要回填的 error
/**
* transform: true
* defaultShowCode: true
*/
import React from 'react';
import { Button, message } from 'antd';
import FormRender, { useForm } from 'form-render';
import { fakeApi } from './utils';
const schema = {
type: 'object',
properties: {
input1: {
title: '简单输入框',
type: 'string',
required: true,
},
select1: {
title: '单选',
type: 'string',
enum: ['a', 'b', 'c'],
enumNames: ['早', '中', '晚'],
},
},
};
const Demo = () => {
const form = useForm();
const onFinish = (data, errors) => {
if (errors.length > 0) {
message.error(
'校验未通过:' + JSON.stringify(errors.map(item => item.name))
);
} else {
fakeApi('xxx/submit', data).then(_ => message.success('提交成功!'));
}
};
// 服务端校验在这里做
const beforeFinish = ({ data, errors, schema, ...rest }) => {
return fakeApi('xxx/validation').then(_ => {
return { name: 'select1', error: ['外部校验错误'] };
});
};
return (
<div style={{ width: '400px' }}>
<FormRender
form={form}
schema={schema}
beforeFinish={beforeFinish}
onFinish={onFinish}
/>
<Button type="primary" onClick={form.submit}>
提交(见console)
</Button>
</div>
);
};
export default Demo;
例 3:bind
接口数据与展示经常会不符,例如 form 的交互是日期范围组件,服务端传的值是 startDate,endDate 两个字段。此时使用 bind 字段
/**
* transform: true
* defaultShowCode: true
*/
import React from 'react';
import { Button, message, Space } from 'antd';
import FormRender, { useForm } from 'form-render';
import { fakeApi } from './utils';
const schema = {
type: 'object',
properties: {
dateRange: {
bind: ['startDate', 'endDate'],
title: '日期范围',
type: 'range',
format: 'date',
},
},
};
const Demo = () => {
const form = useForm();
const onFinish = (data, errors) => {
if (errors.length > 0) {
message.error(
'校验未通过:' + JSON.stringify(errors.map(item => item.name))
);
} else {
fakeApi('xxx/submit', data).then(_ => message.success('提交成功!'));
}
};
const getRemoteData = () => {
fakeApi('xxx/getForm').then(_ => {
form.setValues({ startDate: '2020-04-04', endDate: '2020-04-24' });
});
};
return (
<div style={{ width: '400px' }}>
<FormRender form={form} schema={schema} onFinish={onFinish} />
<Space>
<Button onClick={getRemoteData}>加载服务端数据</Button>
<Button type="primary" onClick={form.submit}>
提交(见console)
</Button>
</Space>
</div>
);
};
export default Demo;
例 4:服务端加载选择框的选项
服务端获取数据后展示下拉选项的选项值,我们提供了 form.setSchemaByPath
方法
/**
* transform: true
* defaultShowCode: true
*/
import React, { useEffect } from 'react';
import { Button, message } from 'antd';
import FormRender, { useForm } from 'form-render';
import { fakeApi } from './utils';
const schema = {
type: 'object',
properties: {
input1: {
title: '简单输入框',
type: 'string',
required: true,
},
obj1: {
title: '对象',
description: '这是一个对象类型',
type: 'object',
properties: {
select1: {
title: '单选',
type: 'string',
widget: 'select',
},
},
},
},
};
const Demo = () => {
const form = useForm();
const onMount = () => {
form.setSchemaByPath('obj1.select1', {
enum: ['east', 'south', 'west', 'north'],
enumNames: ['东', '南', '西', '北'],
});
};
const onFinish = (data, errors) => {
if (errors.length > 0) {
message.error(
'校验未通过:' + JSON.stringify(errors.map(item => item.name))
);
} else {
message.info(JSON.stringify(data));
}
};
return (
<div style={{ width: '400px' }}>
<FormRender
form={form}
schema={schema}
onMount={onMount}
onFinish={onFinish}
/>
<Button type="primary" onClick={form.submit}>
提交(见console)
</Button>
</div>
);
};
export default Demo;