order: 4 group: order: 3 title: 高级用法
toc: false
表单方法(form)
FormRender v1.x 使用了状态内置的模型,所以外部对表单的所有操作都依赖于 form 实例提供的方法。 本篇会 cover 以下这些常用 api:
form.submitform.setValuesform.setValueByPathform.setSchemaByPath
以及以下的生命周期
beforeFinishonFinish
我们写一个最常用的场景:加载一个已经填写完成的表单,从服务端异步获取数据(这里使用 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' }}><FormRenderform={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' }}><FormRenderform={form}schema={schema}onMount={onMount}onFinish={onFinish}/><Button type="primary" onClick={form.submit}>提交(见console)</Button></div>);};export default Demo;
