Gathering detailed insights and metrics for @ifcloud-formily/react-schema-renderer
Gathering detailed insights and metrics for @ifcloud-formily/react-schema-renderer
Gathering detailed insights and metrics for @ifcloud-formily/react-schema-renderer
Gathering detailed insights and metrics for @ifcloud-formily/react-schema-renderer
📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3
npm install @ifcloud-formily/react-schema-renderer
Typescript
Module System
Node Version
NPM Version
TypeScript (78.44%)
Vue (13.05%)
JavaScript (3.87%)
SCSS (2.75%)
Less (1.62%)
Stylus (0.18%)
EJS (0.09%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
12,072 Stars
3,164 Commits
1,550 Forks
165 Watchers
10 Branches
208 Contributors
Updated on Jul 14, 2025
Latest Version
1.5.6
Package Id
@ifcloud-formily/react-schema-renderer@1.5.6
Unpacked Size
286.97 kB
Size
58.68 kB
File Count
64
NPM Version
lerna/3.22.1/node@v12.19.0+x64 (linux)
Node Version
12.19.0
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
6
5
1
English | 简体中文
Schema rendering engine, the package mainly relies on @ifcloud-formily/react, its responsibilities are very simple, the core does two things:
- Parse the Form Schema protocol, recursive rendering
- Manage custom components
1npm install --save @ifcloud-formily/react-schema-renderer
get
merge
getEmptyValue
getSelfProps
getExtendsRules
getExtendsRequired
getExtendsEditable
getExtendsVisible
getExtendsDisplay
getExtendsTriggerType
getExtendsProps
getExtendsComponent
getExtendsComponentProps
getExtendsRenderer
getExtendsEffect
setProperty
setProperties
setArrayItems
getOrderProperties
mapProperties
toJSON
fromJSON
isObject
isArray()
If you are developing directly based on @ifcloud-formily/react-schema-renderer, then you must register your custom component before development. Go to the renderer, otherwise our JSON-Schema protocol can't render the form. And so:
1import React from 'react' 2import { 3 SchemaForm, 4 registerFormField, 5 connect 6} from '@ifcloud-formily/react-schema-renderer' 7 8registerFormField( 9 'string', 10 connect()(({ value, onChange }) => { 11 return <input value={value} onChange={onChange} /> 12 }) 13) 14 15export default () => { 16 return ( 17 <SchemaForm 18 schema={{ 19 type: 'object', 20 properties: { 21 input: { 22 type: 'string' 23 } 24 } 25 }} 26 onChange={console.log} //{input:'this is your input string'} 27 /> 28 ) 29}
Great workmanship, this is the easiest way to use, the core is to register components, and then use the protocol to render.**One thing to note is that we used the connect function when registering components,The function of this connect function is to allow any component to be registered in the SchemaForm as long as it supports the value/onChange API.At the same time, the connect function also shields the Field API, so components that use the connect function cannot be more powerfully extended. The detailed connect API will be introduced later. ** At the same time, one thing to note is that if we want to access a set of component libraries, most of the component libraries in the industry have their Form and FormItem components.Their core is used to control styles, FormItem controls form local styles, and Form controls global form styles,So in a production environment, we need to register the Form and FormItem components so that the style is consistent with the original solution.How to register specifically, we will introduce in detail later.
Speaking of JSON Schema, the above example has been covered. Of course, it is not complicated enough. Let's look at a more complicated example:
1import React from 'react' 2import { SchemaForm } from '@ifcloud-formily/react-schema-renderer' 3 4registerFormField( 5 'string', 6 connect()(({ value, onChange }) => { 7 return <input value={value} onChange={onChange} /> 8 }) 9) 10 11registerFormField('array', () => { 12 return //... 13}) 14 15export default () => { 16 return ( 17 <SchemaForm 18 schema={{ 19 type: 'object', 20 properties: { 21 array: { 22 type: 'array', 23 items: { 24 type: 'object', 25 properties: { 26 input: { 27 type: 'string' 28 } 29 } 30 } 31 } 32 } 33 }} 34 onChange={console.log} //{array:[{input:'This is your input string'}]} 35 /> 36 ) 37}
The above code is a pseudo-code because we didn't register a custom component of type array. Here we don't talk about how to register custom components of the array type. Our core is to analyze how JSON Schema drives form rendering.Note:In SchemaForm, recursive rendering of properties of an object is built-in, but there is no recursive rendering of items with a built-in array.The main reason is that the recursive rendering of an array involves many style requirements, which is not convenient for built-in. So it’s best to leave it to the developer to implement it yourself. So, we will detail how to implement the recursive rendering requirements of the auto-increment list.
JSchema describes JSON Schema in a more elegant way in jsx. We can implement a version of JSchema for the above example:
1import React from 'react' 2import { 3 SchemaMarkupForm as SchemaForm, 4 SchemaMarkupField as Field 5} from '@ifcloud-formily/react-schema-renderer' 6 7export default () => { 8 return ( 9 <SchemaForm 10 onChange={console.log} //{array:[{input:'This is your input string'}]} 11 > 12 <Field type="array" name="array"> 13 <Field type="object"> 14 <Field type="string" name="input" /> 15 </Field> 16 </Field> 17 </SchemaForm> 18 ) 19}
As you can see, using JSchema to describe JSON Schema in your code is more elegant than JSON, greatly improving code maintainability.
In the previous example, we used the registerFormField API to register a custom component, which is the way to register a singleton,Its main advantage is the convenience, but there are also some problems, that is, the single case is easily contaminated, especially in the SPA page.If the developers of different pages are different, because sharing the same memory environment, then A developers may register custom components with the same name as B developers, which can easily lead to online failures.Therefore, we recommend users to use non-single registration methods:
1import React, { useMemo } from 'react' 2import { 3 SchemaForm, 4 registerFormField, 5 connect 6} from '@ifcloud-formily/react-schema-renderer' 7 8const StringField = connect()(({ value, onChange }) => { 9 return <input value={value} onChange={onChange} /> 10}) 11 12const useFields = () => 13 useMemo(() => { 14 string: StringField 15 }) 16 17export default () => { 18 return ( 19 <SchemaForm 20 fields={useFields()} 21 schema={{ 22 type: 'object', 23 properties: { 24 input: { 25 type: 'string' 26 } 27 } 28 }} 29 onChange={console.log} //{input:'this is your input string'} 30 /> 31 ) 32}
In the above example, we mainly pass the custom component in the props dimension of SchemaForm, so that we can guarantee the instance-level registration. This form is very friendly to the SPA.At the same time,It should be noted that we abstracted a React Hook of useFields, which is mainly used to solve the React Virtual DOM recalculation when the component is rendered multiple times, thus avoiding the repeated rendering of the form component.
Because @ifcloud-formily/react-schema-renderer is a base library, no component library is integrated by default. so in actual business development, If you want to customize it based on it, you have to face the problem of accessing third-party component libraries. How to access the third-party component library, let's divide it into the following steps:
Let's take a step by step access to third-party component libraries! Here we mainly use the antd component library as an example.
The access method currently provides a global registration mechanism and a singleton registration mechanism. Global registration is mainly registered using two APIs, registerFormComponent and registerFormItemComponent.Singleton registration is to upload formComponent and formItemComponent directly in the SchemaForm property. If it is a SPA scene, it is recommended to use the singleton registration method. Let's look at the example below:
1import React from 'react' 2import { 3 SchemaForm, 4 registerFormComponent, 5 registerFormItemComponent 6} from '@ifcloud-formily/react-schema-renderer' 7import { Form } from 'antd' 8 9export const CompatFormComponent = ({ children, ...props }) => { 10 return <Form {...props}>{children}</Form> //Very simple to use the Form component, props is the props of the SchemaForm component, here will be directly transparent 11} 12 13export const CompatFormItemComponent = ({ children, ...props }) => { 14 const messages = [].concat(props.errors || [], props.warnings || []) 15 let status = '' 16 if (props.loading) { 17 status = 'validating' 18 } 19 if (props.invalid) { 20 status = 'error' 21 } 22 if (props.warnings && props.warnings.length) { 23 status = 'warning' 24 } 25 return ( 26 <Form.Item 27 {...props} 28 label={props.schema.title} 29 help={ 30 messages.length ? messages : props.schema && props.schema.description 31 } 32 validateStatus={status} 33 > 34 {children} 35 </Form.Item> 36 ) 37} 38 39/*** 40Global registration method 41registerFormComponent(CompatFormComponent) 42registerFormItemComponent(CompatFormItemComponent) 43***/ 44 45//Single case registration method 46export default () => { 47 return ( 48 <SchemaForm 49 formComponent={CompatFormComponent} 50 formItemComponent={CompatFormItemComponent} 51 /> 52 ) 53}
We can see that extending the overall or partial style of the form can be easily solved by simply extending the Form/FormItem component. It should be noted here that the props received by the FormItem component are a bit complicated. Don't worry, the detailed props API will be listed later. Now we just need to know how it is probably registered.
all components of the component library are atomic components, most of them are compatible with the value/onChange specification, so we can quickly access the components of the component library with the connect function. Usually, if we need access to the component library component, we probably do three things:
Let's take an example of InputNumber:
1import React from 'react' 2import { connect, registerFormField } from '@ifcloud-formily/react-schema-renderer' 3import { InputNumber } from 'antd' 4 5const mapTextComponent = ( 6 Target: React.JSXElementConstructor<any>, 7 props: any = {}, 8 fieldProps: any = {} 9): React.JSXElementConstructor<any> => { 10 const { editable } = fieldProps 11 if (editable !== undefined) { 12 if (editable === false) { 13 return PreviewText 14 } 15 } 16 if (Array.isArray(props.dataSource)) { 17 return Select 18 } 19 return Target 20} 21 22const mapStyledProps = ( 23 props: IConnectProps, 24 fieldProps: MergedFieldComponentProps 25) => { 26 const { loading, errors } = fieldProps 27 if (loading) { 28 props.state = props.state || 'loading' 29 } else if (errors && errors.length) { 30 props.state = 'error' 31 } 32} 33 34const acceptEnum = (component: React.JSXElementConstructor<any>) => { 35 return ({ dataSource, ...others }) => { 36 if (dataSource) { 37 return React.createElement(Select, { dataSource, ...others }) 38 } else { 39 return React.createElement(component, others) 40 } 41 } 42} 43 44registerFormField( 45 'number', 46 connect({ 47 getProps: mapStyledProps, //Process state map 48 getComponent: mapTextComponent //Process details 49 })(acceptEnum(InputNumber)) //Process enumeration states 50)
In this example, we use the connect function in depth. Connect is a HOC. During the rendering phase, it can add some intermediate processing logic to the component rendering process to help dynamic distribution. Of course, connect has a lot of APIs, which will be covered in detail later.
JSON Schema describes the form of data structure, which is supported by nature. But the form ends up at the UI level. Unfortunately, at the UI level, we have a lot of components that are not a specific data node of JSON Schema. It's just a UI node. So, how to do to describe complex layouts in JSON Schema?
Now formily's approach is to abstract a concept called virtual nodeAfter the user specifies a JSON Schema x-component as a virtual node at the code level, whether it is rendering, data processing, or final data submission, as long as the node is virtual, it will not be treated as a normal data node. So, with the concept of this virtual node, we can describe various complex layouts in JSON Schema. Let's try to write a layout component:
1import React from 'react' 2import { SchemaForm, registerVirtualBox } from '@ifcloud-formily/react-schema-renderer' 3import { Card } from 'antd' 4 5registerVirtualBox('card', ({ children, ...props }) => { 6 return <Card {...props.schema.getExtendsComponentProps()}>{children}</Card> 7}) 8 9export default () => { 10 return ( 11 <SchemaForm 12 schema={{ 13 type: 'object', 14 properties: { 15 layout_card: { 16 //layout_cardThe name of this property, whatever you change will not affect the final submitted data structure 17 type: 'object', 18 'x-component': 'card', 19 'x-component-props': { 20 title: 'This is Card' 21 }, 22 properties: { 23 array: { 24 type: 'array', 25 items: { 26 type: 'object', 27 properties: { 28 input: { 29 type: 'string' 30 } 31 } 32 } 33 } 34 } 35 } 36 } 37 }} 38 /> 39 ) 40}
From this pseudo-code, we can see that the card is a normal Object Schema node, just need to specify an x-component as card, so that it can match the card registered by registerVirtualBox, it will achieve the effect of virtual node. So, no matter what you change the name of the property in JSON Schema, it will not affect the final submitted data structure.It should be noted here that x-component-props is directly passed to the callback function parameters of registerVirtualBox. This is the use of the JSON Schema form, and we also use JSchema:
1import React from 'react' 2import { SchemaForm, createVirtualBox } from '@ifcloud-formily/react-schema-renderer' 3import { Card } from 'antd' 4 5const Card = createVirtualBox('card', ({ children, ...props }) => { 6 return <Card {...props}>{children}</Card> 7}) 8 9export default () => { 10 return ( 11 <SchemaForm> 12 <Card title="This is Card"> 13 <Field type="array" name="array"> 14 <Field type="object"> 15 <Field type="string" name="input" /> 16 </Field> 17 </Field> 18 </Card> 19 </SchemaForm> 20 ) 21}
From this example we can see that with the createVirtualBox API you can quickly create a layout component that you can use directly in JSchema.In fact, the internal implementation of createVirtualBox is very simple, just use registerVitualBox and SchemaMarkupField:
1import React from 'react' 2import { SchemaMarkupField as Field } from '@ifcloud-formily/react-schema-renderer' 3export function createVirtualBox<T = {}>( 4 key: string, 5 component?: React.JSXElementConstructor<React.PropsWithChildren<T>> 6) { 7 registerVirtualBox( 8 key, 9 component 10 ? ({ props, schema, children }) => { 11 return React.createElement(component, { 12 ...schema.getExtendsComponentProps(), 13 children 14 }) 15 } 16 : () => <Fragment /> 17 ) 18 const VirtualBox: React.FC<T & { name?: string }> = ({ 19 children, 20 name, 21 ...props 22 }) => { 23 return ( 24 <Field 25 type="object" 26 name={name} 27 x-component={key} 28 x-props={props} 29 x-component-props={props} 30 > 31 {children} 32 </Field> 33 ) 34 } 35 return VirtualBox 36}
The way to register the layout components described above is a singleton registration. If we need registration in the form of an instance, it is still similar to the way we said earlier.
1import React from 'react' 2import { Card as AntdCard } from 'antd' 3const Card = ({children,...props})=>{ 4 return <AntdCard {...props.schema.getExtendsComponentProps()}>{children}</Card> 5} 6 7export default ()=>{ 8 return ( 9 <SchemaForm 10 virtualFields={{ 11 card:Card 12 }} 13 schema={{ 14 type:"object", 15 properties:{ 16 layout_card:{//layout_cardThe name of this property, whatever you change will not affect the final submitted data structure 17 type:"object", 18 "x-component":"card", 19 "x-component-props":{ 20 title:"This is Card" 21 }, 22 properties:{ 23 array:{ 24 type:"array", 25 items:{ 26 type:"object", 27 properties:{ 28 input:{ 29 type:"string" 30 } 31 } 32 } 33 } 34 } 35 } 36 } 37 }} 38 /> 39 ) 40}
What is a recursive rendering component? In fact, implement the components of properties and items in JSON Schema,sucn astype:"string"
This kind of node belongs to the atomic node and is not a recursive rendering component. The layout component mentioned above, it is also a recursive rendering component, but it fixes the rendering mode, so it can be easily registered. So, most of us want to implement recursive rendering of the scene,Perhaps more of a scene in`type:"array"will implement recursive rendering. Below we will detail the implementation of the auto-increment list component.
The self-increment list has several main features:
In order to help you better understand how to implement the auto-increment list component, we will not implement the specific style, and more is to teach you how to implement recursive rendering and array item operations. Let us look at the pseudo-code:
1import React, { Fragment } from 'react' 2import { 3 registerFormField, 4 SchemaField, 5 FormPath 6} from '@ifcloud-formily/react-schema-renderer' 7 8//No need to pack with connet 9registerFormField('array', ({ value, path, mutators }) => { 10 const emptyUI = ( 11 <button 12 onClick={() => { 13 mutators.push() 14 }} 15 > 16 Add Element 17 </button> 18 ) 19 20 const listUI = value.map((item, index) => { 21 return ( 22 <div key={index}> 23 <SchemaField path={FormPath.parse(path).concat(index)} /> 24 <button 25 onClick={() => { 26 mutators.remove(index) 27 }} 28 > 29 remove 30 </button> 31 <button 32 onClick={() => { 33 mutators.moveDown(index) 34 }} 35 > 36 move down 37 </button> 38 <button 39 onClick={() => { 40 mutators.moveUp(index) 41 }} 42 > 43 move up 44 </button> 45 </div> 46 ) 47 }) 48 49 return value.length == 0 ? emptyUI : listUI 50})
To implement a self-incrementing list component with recursive rendering is super simple. On the contrary, it would be a bit cumbersome to implement related styles. In short, the core is to use the SchemaField component and the mutators API, the specific API will be described in detail later.
This problem is no solution in the old Formily.It happens that because our business complexity is high to a certain extent, we are limited by this problem, so we must find a way to solve this problem. We can define what is a super complex custom component:
There are a large number of form components inside the component, and there are also a large number of linkage relationships inside.
There is a private server dynamic rendering scheme inside the component.
There is a complex layout structure inside the component
In these three points, meet the characteristics of ultra-complex custom components, For this scenario, why can't we solve the problem by properly encapsulating the form of a custom component? In fact, it is mainly limited to verification, there is no way to check the whole, so we need an ability to aggregate a large amount of field processing logic. Let's take a look at the specific solution:
1import React, { Fragment } from 'react' 2import { 3 registerFormField, 4 SchemaField, 5 FormPath, 6 InternalField, 7 useFormEffects, 8 FormEffectHooks 9} from '@ifcloud-formily/react-schema-renderer' 10import { Input, Form } from 'antd' 11 12const FormItem = ({ component, ...props }) => { 13 return ( 14 <InternalField {...props}> 15 {({ state, mutators }) => { 16 const messages = [].concat(state.errors || [], state.warnings || []) 17 let status = '' 18 if (state.loading) { 19 status = 'validating' 20 } 21 if (state.invalid) { 22 status = 'error' 23 } 24 if (state.warnings && state.warnings.length) { 25 status = 'warning' 26 } 27 return ( 28 <Form.Item 29 {...props} 30 help={messages.length ? messages : props.help && props.help} 31 validateStatus={status} 32 > 33 {React.createElement(component, { 34 ...state.props, 35 value: state.value, 36 onChange: mutators.change, 37 onBlur: mutators.blur, 38 onFocus: mutators.focus 39 })} 40 </Form.Item> 41 ) 42 }} 43 </InternalField> 44 ) 45} 46 47//No need to pack with connet 48registerFormField('complex', ({ path }) => { 49 useFormEffects(({ setFieldState }) => { 50 FormEffectHooks.onFieldValueChange$('ccc').subscribe(({ value }) => { 51 if (value === '123') { 52 setFieldState('ddd', state => { 53 state.value = 'this is linkage relationship' 54 }) 55 } 56 }) 57 }) 58 59 return ( 60 <> 61 <FormItem name={FormPath.parse(path).concat('aaa')} component={Input} /> 62 <FormItem name={FormPath.parse(path).concat('bbb')} component={Input} /> 63 <FormItem name="ccc" component={Input} /> 64 <FormItem name="ddd" component={Input} /> 65 </> 66 ) 67})
In this pseudo-code, we mainly use two core APIs, mainly useFormEffects and InternalField,useFormEffects gives developers a place to write the effects logic locally, so that the effects logic can be easily reused. InternalField is the @ifcloud-formily/react Field component. You can take a look at the @ifcloud-formily/react documentation. SchemaForm also uses @ifcloud-formily/react internally, it can share the same Context, so we can easily use InternalField inside a custom component. Also note that when using InternalField directly, the name we registered is the root level name, if you want to reuse the path of the current custom component, you can use FormPath to resolve the path, and then concat.
The overall API fully inherits @ifcloud-formily/core and @ifcloud-formily/react, and only the specific APIs of @ifcloud-formily/react-schema-renderer are listed below.
Custom component registration bridge, a high-level component function (HOC) that is used primarily to quickly access most component library components (components that implement the value/onChange API)
Signature
1connect(options?: IConnectOptions): (component : React.JSXElementConstructor<any>)=>(fieldProps:ISchemaFieldComponentProps)=>JSX.Element
Usage
1import { registerFormField, connect } from '@ifcloud-formily/react-schema-renderer' 2import { Select } from 'antd' 3registerFormField('select', connect()(Select))
Register custom component functions
Signature
1registerFormField( 2 name:string, 3 component: React.JSXElementConstructor<ISchemaFieldComponentProps> 4)
Bulk registration of custom components
Signature
1registerFormFields( 2 fieldsMap: { 3 [key : string]: React.JSXElementConstructor<ISchemaFieldComponentProps> 4 } 5)
Register Form Style Component
Signature
1registerFormComponent<Props>( 2 component:React.JSXElementConstructor<Props> 3)
Register the FormItem style component
Signature
1registerFormItemComponent( 2 component:React.JSXElementConstructor<ISchemaFieldComponentProps> 3)
Register the virtual box component, mainly used to describe the layout in JSON Schema
Signature
1registerVirtualBox( 2 name:string, 3 component:React.JSXElementConstructor<ISchemaVirtualFieldComponentProps> 4)
Create a virtual box component, the returned component can be used directly in SchemaMarkupForm
Signature
1createVirtualBox<Props>( 2 name:string, 3 component:React.JSXElementConstructor<Props> 4) : React.FC<Props>
Usage
1import React from 'react' 2import { 3 SchemaMarkupForm as SchemaForm, 4 SchemaMarkupField as Field, 5 createVirtualBox 6} from '@ifcloud-formily/react-schema-renderer' 7import { Card } from 'antd' 8 9const FormCard = createVirtualBox('card', props => { 10 return <Card {...props} /> 11}) 12 13export default () => ( 14 <SchemaForm> 15 <FormCard title="This is card"> 16 <Field name="aaa" type="string" /> 17 </FormCard> 18 </SchemaForm> 19)
Creating a virtual box component, the returned component can be used directly in SchemaMarkupForm, it is different from createVirtualBox mainly because the component receives the props The props received by createVirtualBox is the simplest component props createControllerBox receives
ISchemaVirtualFieldComponentProps
Signature
1createControllerBox<Props>( 2 name:string, 3 component:React.JSXElementConstructor<ISchemaVirtualFieldComponentProps> 4) : React.FC<Props>
Usage
1import React from 'react' 2import { 3 SchemaMarkupForm as SchemaForm, 4 SchemaMarkupField as Field, 5 createControllerBox 6} from '@ifcloud-formily/react-schema-renderer' 7import { Card } from 'antd' 8 9const FormCard = createControllerBox('card', ({ schema, children }) => { 10 return <Card {...schema.getExtendsComponentProps()}>{children}</Card> 11}) 12 13export default () => ( 14 <SchemaForm> 15 <FormCard title="This is card"> 16 <Field name="aaa" type="string" /> 17 </FormCard> 18 </SchemaForm> 19)
Get the registry, all components registered through the registerFormXXX API are managed in the registry
Signature
1getRegistry(): ISchemaFormRegistry
Clear the registry and clear all components registered via the registerFormXXX API
Signature
1cleanRegistry(): void
The whole Class inherits @ifcloud-formily/core completely, such as FormPath and FormLifeCyle. Only the classes specific to @ifcloud-formily/react-schema-renderer are listed below.
The Schema parsing engine, given a data that satisfies the JSON Schema, we will parse it into the corresponding Schema instance, and we can quickly process some things with some tool methods. At the same time, the Schema Class provides a unified protocol difference smoothing capability to ensure Seamless and smooth upgrade when the protocol is upgraded
Attributes
Attribute name | Description | Type |
---|---|---|
title | Field title | React.ReactNode |
name | The parent property name of the field | string |
description | Field description | React.ReactNode |
default | Field default | any |
readOnly | Whether read-only and editable | boolean |
type | Field Type | `'string' |
enum | Enumerate data | `Array<string |
const | Check if the field value is equal to the value of const | any |
multipleOf | Check if the field value can be divisible by the value of multipleOf | number |
maximum | Check the maximum value (greater than) | number |
exclusiveMaximum | Check the maximum value (greater than or equal to) | number |
minimum | Check minimum value (less than) | number |
exclusiveMinimum | Minimum value (less than or equal to) | number |
maxLength | Check maximum length | number |
minLength | Check minimum length | number |
pattern | Regular check rule | `string |
maxItems | Maximum number of entries | number |
minItems | Minimum number of entries | number |
uniqueItems | Whether to check for duplicates | boolean |
maxProperties | Maximum number of attributes | number |
minProperties | Minimum number of attributes | number |
required | Required | boolean |
format | Regular rule type | InternalFormats |
properties | Object property | {[key : string]:Schema} |
items | Array description | `Schema |
additionalItems | Extra array element description | Schema |
patternProperties | Dynamically match the schema of an attribute of an object | {[key : string]:Schema} |
additionalProperties | Schema matching the extra attributes of the object | Schema |
editable | Whether the field is editable | boolean |
visible | Whether the data and style is visible | boolean |
display | Whether the style is visible | boolean |
x-props | Field extension attribute | { [name: string]: any } |
x-index | Field order | number |
x-rules | Field check rule | ValidatePatternRules |
x-component | Field UI component | string |
x-component-props | Field UI component properties | {} |
x-render | Field extension rendering function | <T = ISchemaFieldComponentProps>(props: T & { renderComponent: () => React.ReactElement}) => React.ReactElement |
x-effect | Field side effect trigger | (dispatch: (type: string, payload: any) => void,option?:object) => { [key: string]: any } |
Method
get
Get the Schema child node according to the data path
Signature
1get(path?: FormPathPattern): Schema
Usage
1const schema = new Schema({ 2 type: 'object', 3 properties: { 4 array: { 5 type: 'array', 6 items: { 7 type: 'object', 8 properties: { 9 input: { 10 type: 'string' 11 } 12 } 13 } 14 } 15 } 16}) 17 18schema.get('array[0].input') //{type:"string"}
merge
Merge Schema
Signature
1merge(spec:ISchema): Schema
Usage
1const schema = new Schema({ 2 type: 'object', 3 properties: { 4 array: { 5 type: 'array', 6 items: { 7 type: 'object', 8 properties: { 9 input: { 10 type: 'string' 11 } 12 } 13 } 14 } 15 } 16}) 17 18schema.merge({ 19 title: 'root object' 20}) 21/** 22{ 23 type:"object", 24 title:"root object", 25 properties:{ 26 array:{ 27 type:'array', 28 items:{ 29 type:'object', 30 properties:{ 31 input:{ 32 type:'string' 33 } 34 } 35 } 36 } 37 } 38} 39**/
getEmptyValue
Get the null value of the current Schema based on the type of Schema
Signature
1getEmptyValue() : '' | [] | {} | 0
Usage
1const schema = new Schema({ 2 type: 'object', 3 properties: { 4 array: { 5 type: 'array', 6 items: { 7 type: 'object', 8 properties: { 9 input: { 10 type: 'string' 11 } 12 } 13 } 14 } 15 } 16}) 17 18schema.get('array.0.input').getEmptyValue() // '' 19schema.get('array.0').getEmptyValue() // {} 20schema.get('array').getEmptyValue() // [] 21schema.getEmptyValue() // {}
getSelfProps
Get no nested Schema properties (does not include nested properties like properties/items)
Signature
1getSelfProps() : ISchema
Usage
1const schema = new Schema({ 2 type: 'object', 3 properties: { 4 array: { 5 type: 'array', 6 items: { 7 type: 'object', 8 properties: { 9 input: { 10 type: 'string' 11 } 12 } 13 } 14 } 15 } 16}) 17 18schema.getSelfProps() // { type:"object" }
getExtendsRules
Get the extended check rule. This method is more complicated. It will parse the attributes and x-rules attributes of all the check types of the current Schema, and finally merge them into a unified rules structure.
Signature
1getExtendsRules() : ValidateArrayRules
Usage
1const schema = new Schema({ 2 type:"string", 3 required:true, 4 maxLength:10 5 "x-rules":{ 6 pattern:/^\d+$/ 7 } 8}) 9 10schema.getExtendsRules() // [{required:true},{max:10},{pattern:/^\d+$/}]
getExtendsRequired
Obtaining whether it is required or not is actually reading the required attribute of the Schema. Why is it encapsulated into a method to ensure that the user is not aware of the protocol upgrade? We only need to ensure backward compatibility of the method.
Signature
1getExtendsRequired(): void | boolean
Usage
1const schema = new Schema({ 2 type:"string", 3 required:true, 4 maxLength:10 5 "x-rules":{ 6 pattern:/^\d+$/ 7 } 8}) 9 10schema.getExtendsRequired() // true
getExtendsEditable
Get the editable state of the Schema, consistent with the getExtendsEditable ability, also to smooth out the protocol differences
Signature
1getExtendsEditable() : void | boolean
Usage
1const schema1 = new Schema({ 2 type: 'string', 3 editable: false 4}) 5 6schema1.getExtendsEditable() // false 7 8const schema2 = new Schema({ 9 type: 'string', 10 readOnly: true 11}) 12 13schema2.getExtendsEditable() // false 14 15const schema3 = new Schema({ 16 type: 'string', 17 'x-props': { 18 editable: false 19 } 20}) 21 22schema3.getExtendsEditable() // false 23 24const schema4 = new Schema({ 25 type: 'string', 26 'x-component-props': { 27 editable: false 28 } 29}) 30 31schema4.getExtendsEditable() // false
getExtendsVisible
Get data and style visible property
签名
1getExtendsVisible(): boolean
getExtendsDisplay
Get style visible property
签名
getExtendsDisplay() : boolean
getExtendsTriggerType
Get the triggerType, which is consistent with the getExtendsTriggerType capability, and is capable of providing protocol differences.
Signature
1getExtendsTriggerType() : 'onBlur' | 'onChange' | string
Usage
1const schema1 = new Schema({ 2 type: 'string', 3 'x-props': { 4 triggerType: 'onBlur' 5 } 6}) 7 8schema1.getExtendsTriggerType() // onBlur 9 10const schema2 = new Schema({ 11 type: 'string', 12 'x-component-props': { 13 triggerType: 'onBlur' 14 } 15}) 16 17schema2.getExtendsTriggerType() // onBlur 18 19const schema3 = new Schema({ 20 type: 'string', 21 'x-item-props': { 22 triggerType: 'onBlur' 23 } 24}) 25 26schema3.getExtendsTriggerType() // onBlur
getExtendsProps
Get the x-props attribute
Signature
1getExtendsProps() : {}
getExtendsComponent
Get the x-props attribute
Signature
1getExtendsComponent() : string
getExtendsComponentProps
Get the x-component-props property, which is the component property of the x-component
Signature
1getExtendsComponentProps() : {}
getExtendsRenderer
Get the x-render attribute
Signature
1getExtendsRenderer() : <T = ISchemaFieldComponentProps>( 2 props: T & { 3 renderComponent: () => React.ReactElement 4 } 5 ) => React.ReactElement
getExtendsEffect
Get the x-effect attribute
Signature
1getExtendsEffect() : ( 2 dispatch: (type: string, payload: any) => void, 3 option?: object 4) => { [key: string]: any }
setProperty
Set properties for the current schema
Signature
1setProperty(key: string, schema: ISchema): Schema
setProperties
Set properties for the current Schema batch
Signature
1setProperties(properties: {[key : string]:ISchema}) : {[key : string]:Schema}
setArrayItems
Set the items property to the current schema
Signature
1setArrayItems(schema:Ischema) : Schema
getOrderProperties
Give all properties in x-index order
Signature
1getOrderProperties() : {schema:Schema,key:string}[]
mapProperties
Traverse the properties of the schema in order (x-index)
Signature
1mapProperties(callback?: (schema: Schema, key: string) => any):any[]
toJSON
Output no loop dependent json data structure
Signature
toJSON() : ISchema
fromJSON
Generate a Schema object based on a json parsing
Signature
1fromJSON(json : ISchema) : Schema
isObject
Determine whether the current schema is an object type
Signature
isObject() : boolean
isArray()
Determine if the current schema is an array type
Signature
isArray() : boolean
The whole component is completely inherited @ifcloud-formily/react, only the components specific to @ifcloud-formily/react-schema-renderer are listed below.
<SchemaForm/>
The core JSON Schema rendering component
Attributes
1interface ISchemaFormProps< 2 Value = any, 3 DefaultValue = any, 4 FormEffectPayload = any, 5 FormActions = ISchemaFormActions | ISchemaFormAsyncActions 6> { 7 //Form value 8 value?: Value 9 //Form default value 10 defaultValue?: DefaultValue 11 //Form default value, weakly controlled 12 initialValues?: DefaultValue 13 //Form actions 14 actions?: FormActions 15 //Form effects 16 effects?: IFormEffect<FormEffectPayload, FormActions> 17 //Form instance 18 form?: IForm 19 //Form change callback 20 onChange?: (values: Value) => void 21 //Form submission callback 22 onSubmit?: (values: Value) => void | Promise<Value> 23 //Form reset callback 24 onReset?: () => void 25 //Form validation failure callback 26 onValidateFailed?: (valideted: IFormValidateResult) => void 27 //Form child node 28 children?: React.ReactElement 29 //Whether to open the dirty check 30 useDirty?: boolean 31 //Is it editable 32 editable?: boolean | ((name: string) => boolean) 33 //Whether to enable pessimistic verification, if the first verification fails, stop the remaining verification 34 validateFirst?: boolean 35 //Form Schema object 36 schema?: ISchema 37 //Instance level registration custom component 38 fields?: ISchemaFormRegistry['fields'] 39 //Instance level registration virtual box component 40 virtualFields?: ISchemaFormRegistry['virtualFields'] 41 //Instance level registration Form style component 42 formComponent?: ISchemaFormRegistry['formComponent'] 43 //Instance level registration FormItem style component 44 formItemComponent?: ISchemaFormRegistry['formItemComponent'] 45}
<SchemaField/>
Based on a Data Path, it automatically finds and renders the internal components of the Schema node, mainly used to implement recursive rendering within the custom component.
Attributes
1interface ISchemaFieldProps { 2 //Data path 3 path?: FormPathPattern 4}
<SchemaMarkupForm/>
Let SchemaForm support the Form component of jsx tabbed notation, which needs to be used together with SchemaMarkupField
Attributes
1interface ISchemaFormProps< 2 Value = any, 3 DefaultValue = any, 4 FormEffectPayload = any, 5 FormActions = ISchemaFormActions | ISchemaFormAsyncActions 6> { 7 //Form value 8 value?: Value 9 //Form default value 10 defaultValue?: DefaultValue 11 //Form default value, weakly controlled 12 initialValues?: DefaultValue 13 //Form actions 14 actions?: FormActions 15 //Form effects 16 effects?: IFormEffect<FormEffectPayload, FormActions> 17 //Form instance 18 form?: IForm 19 //Form change callback 20 onChange?: (values: Value) => void 21 //Form submission callback 22 onSubmit?: (values: Value) => void | Promise<Value> 23 //Form reset callback 24 onReset?: () => void 25 //Form validation failure callback 26 onValidateFailed?: (valideted: IFormValidateResult) => void 27 //Form child node 28 children?: React.ReactElement 29 //Whether to open the dirty check 30 useDirty?: boolean 31 //Is it editable 32 editable?: boolean | ((name: string) => boolean) 33 //Whether to enable pessimistic verification, if the first verification fails, stop the remaining verification 34 validateFirst?: boolean 35 //Form Schema object 36 schema?: ISchema 37 //Instance level registration custom component 38 fields?: ISchemaFormRegistry['fields'] 39 //Instance level registration virtual box component 40 virtualFields?: ISchemaFormRegistry['virtualFields'] 41 //Instance level registration Form style component 42 formComponent?: ISchemaFormRegistry['formComponent'] 43 //Instance level registration FormItem style component 44 formItemComponent?: ISchemaFormRegistry['formItemComponent'] 45}
Usage
1import { 2 SchemaMarkupForm as SchemaForm, 3 SchemaMarkupField as Field 4} from '@ifcloud-formily/react-schema-renderer' 5 6export default () => { 7 return ( 8 <SchemaForm> 9 <Field name="aa" type="string" /> 10 </SchemaForm> 11 ) 12}
<SchemaMarkupField/>
The SchemaForm supports the Field component of jsx tabbed notation, which needs to be used together with SchemaMarkupForm
Attributes
1type IMarkupSchemaFieldProps = ISchema
<InternalForm/>
The core Form is the same as the Form component in @ifcloud-formily/react
<InternalField/>
The core Field, like the Field component in @ifcloud-formily/react, is mainly used in complex custom components.
Inheriting @ifcloud-formily/react and @ifcloud-formily/core's Interfaces as a whole, only @ifcloud-formily/react-schema-renderer are listed below.
Connect parameters for registered components
1interface IConnectOptions { 2 valueName?: string //value name 3 eventName?: string //get value callback name 4 defaultProps?: {} //component default props 5 getValueFromEvent?: (event?: any, value?: any) => any //get value from event callback. 6 getProps?: ( 7 //props transformer 8 componentProps: {}, 9 fieldProps: MergedFieldComponentProps 10 ) => {} | void 11 getComponent?: ( 12 //component transformer 13 Target: any, 14 componentProps: {}, 15 fieldProps: MergedFieldComponentProps 16 ) => React.JSXElementConstructor<any> 17}
It is very important to customize the properties received by the component. As long as it involves developing custom components, you need to understand the protocol.
1interface ISchemaFieldComponentProps { 2 //State name, FieldState 3 displayName?: string 4 //Data path 5 name: string 6 //Node path 7 path: string 8 //Whether it has been initialized 9 initialized: boolean 10 //Whether it is in the original state, the state is true only when value===intialValues 11 pristine: boolean 12 //Whether it is in a legal state, as long as the error length is greater than 0, the valid is false. 13 valid: boolean 14 //Whether it is in an illegal state, as long as the error length is greater than 0, the valid is true. 15 invalid: boolean 16 //Is it in check state? 17 validating: boolean 18 //Whether it is modified, if the value changes, the property is true and will be true for the entire lifetime of the field. 19 modified: boolean 20 //Whether it is touched 21 touched: boolean 22 //Whether it is activated, it will be triggered to true when the field triggers the onFocus event, and false when onBlur is triggered. 23 active: boolean 24 //Whether it has been accessed, when the field triggers the onBlur event, it will be triggered to true 25 visited: boolean 26 //Is it visible, note: if the status is false, the value of the field will not be submitted, and the UI will not display 27 visible: boolean 28 //Whether to show, note: if the status is false, then the value of the field will be submitted, the UI will not display, similar to the form hidden field 29 display: boolean 30 //Is it editable 31 editable: boolean 32 //Whether it is in the loading state, note: if the field is in asynchronous check, loading is true 33 loading: boolean 34 //The field has multiple parameters. For example, when the field onChange is triggered, multi-parameter data is passed to the event callback, then the values of all parameters are stored here. 35 values: any[] 36 //Field error message 37 errors: string[] 38 //Field alert message 39 warnings: string[] 40 //Field value, which is constant equal to values[0] 41 value: any 42 //Initial value 43 initialValue: any 44 //Verification rules, specific type descriptions refer to the following documents 45 rules: ValidatePatternRules[] 46 //Required or not 47 required: boolean 48 //Has it been mounted? 49 mounted: boolean 50 //Has it been unmounted? 51 unmounted: boolean 52 //Field extension property, under the SchemaForm ISchema structure 53 props: ISchema 54 //The schema object of the current field 55 schema: Schema 56 //Current operation data set of the field 57 mutators: IMutators 58 //Form instance 59 form: IForm 60 //Recursive rendering function 61 renderField: ( 62 addtionKey: string | number, 63 reactKey?: string | number 64 ) => React.ReactElement 65}
The attributes received by the virtual field component, as long as it involves registering the virtual field, you need to understand the protocol.
1interface ISchemaVirtualFieldComponentProps { 2 //State name, VirtualFieldState 3 displayName: string 4 //Field data path 5 name: string 6 //Field node path 7 path: string 8 //Whether it has been initialized 9 initialized: boolean 10 //Is it visible, note: if the status is false, the UI will not be displayed, and the data will not be submitted (because it is a VirtualField) 11 visible: boolean 12 //Whether to show, note: if the state is false, the UI will not be displayed, and the data will not be submitted (because it is a VirtualField) 13 display: boolean 14 //Has it been mounted? 15 mounted: boolean 16 //Has it been unmounted? 17 unmounted: boolean 18 //Field extension attribute 19 props: ISchema 20 //The schema object of the current field 21 schema: Schema 22 //Form instance 23 form: IForm 24 //Child element 25 children: React.ReactElement[] 26 //Recursive rendering function 27 renderField: ( 28 addtionKey: string | number, 29 reactKey?: string | number 30 ) => React.ReactElement 31}
The component registry, whether it is a normal field, a virtual field, or a Form/FormItem will be registered here.
1interface ISchemaFormRegistry { 2 fields: { 3 [key: string]: React.JSXElementConstructor<ISchemaFieldComponentProps> 4 } 5 virtualFields: { 6 [key: string]: React.JSXElementConstructor< 7 ISchemaVirtualFieldComponentProps 8 > 9 } 10 formItemComponent: React.JSXElementConstructor<ISchemaFieldComponentProps> 11 formComponent: string | React.JSXElementConstructor<any> 12}
Schema protocol object, mainly used to constrain a json structure to satisfy the Schema protocol
1interface ISchema { 2 /** base json schema spec**/ 3 title?: React.ReactNode 4 description?: React.ReactNode 5 default?: any 6 readOnly?: boolean 7 writeOnly?: boolean 8 type?: 'string' | 'object' | 'array' | 'number' | string 9 enum?: Array<string | number | { label: React.ReactNode; value: any }> 10 const?: any 11 multipleOf?: number 12 maximum?: number 13 exclusiveMaximum?: number 14 minimum?: number 15 exclusiveMinimum?: number 16 maxLength?: number 17 minLength?: number 18 pattern?: string | RegExp 19 maxItems?: number 20 minItems?: number 21 uniqueItems?: boolean 22 maxProperties?: number 23 minProperties?: number 24 required?: string[] | boolean 25 format?: string 26 /** nested json schema spec **/ 27 properties?: { 28 [key: string]: ISchema 29 } 30 items?: ISchema | ISchema[] 31 additionalItems?: ISchema 32 patternProperties?: { 33 [key: string]: ISchema 34 } 35 additionalProperties?: ISchema 36 /** extend json schema specs */ 37 visible?: boolean //Field initial visible status(Whether the data is visible) 38 display?: boolean //Field initial display status(Whether the style is visible) 39 editable?: boolean 40 ['x-props']?: { [name: string]: any } 41 ['x-index']?: number 42 ['x-rules']?: ValidatePatternRules 43 ['x-linkages']?: Array<{ 44 target: FormPathPattern 45 type: string 46 [key: string]: any 47 }> 48 ['x-mega-props']?: { [name: string]: any } 49 ['x-component']?: string 50 ['x-component-props']?: { [name: string]: any } 51 ['x-render']?: <T = ISchemaFieldComponentProps>( 52 props: T & { 53 renderComponent: () => React.ReactElement 54 } 55 ) => React.ReactElement 56 ['x-effect']?: ( 57 dispatch: (type: string, payload: any) => void, 58 option?: object 59 ) => { [key: string]: any } 60}
The core actions inherit @ifcloud-formily/react's IFormActions, mainly adding the getSchema API
1interface ISchemaFormActions extends IFormActions { 2 getSchema(): Schema 3 getFormSchema(): Schema 4}
Core actions inherit @ifcloud-formily/react's IFormAsyncActions, mainly adding the getSchema API
1interface ISchemaFormAsyncActions extends IFormAsyncActions { 2 getSchema(): Promise<Schema> 3 getFormSchema(): Promise<Schema> 4}
Calibration result
1interface IFormValidateResult { 2 errors: Array<{ 3 path: string 4 messages: string[] 5 }> 6 warnings: Array<{ 7 path: string 8 messages: string[] 9 }> 10}
Built-in format checksum
1type InternalFormats = 2 | 'url' 3 | 'email' 4 | 'ipv6' 5 | 'ipv4' 6 | 'idcard' 7 | 'taodomain' 8 | 'qq' 9 | 'phone' 10 | 'money' 11 | 'zh' 12 | 'date' 13 | 'zip' 14 | string
Original check description
1interface ValidateDescription { 2 // built-in rules,ref: string rules 3 format?: InternalFormats 4 // custom validation 5 validator?: CustomValidator 6 // required 7 required?: boolean 8 // pattern 9 pattern?: RegExp | string 10 // max length 11 max?: number 12 // maximum 13 maximum?: number 14 // exclusiveMaximum 15 exclusiveMaximum?: number 16 // exclusiveMinimum 17 exclusiveMinimum?: number 18 // minimum 19 minimum?: number 20 // min 21 min?: number 22 // length 23 len?: number 24 // whitespace 25 whitespace?: boolean 26 // enum 27 enum?: any[] 28 // error message 29 message?: string 30 [key: string]: any 31}
1type SyncValidateResponse = 2 | null 3 | string 4 | boolean 5 | { 6 type?: 'error' | 'warning' 7 message: string 8 } 9type AsyncValidateResponse = Promise<SyncValidateResponse> 10type ValidateResponse = SyncValidateResponse | AsyncValidateResponse
Custom check function
1type CustomValidator = ( 2 value: any, 3 description?: ValidateDescription 4) => ValidateResponse
Verification rule set
1type ValidatePatternRules = 2 | InternalFormats 3 | CustomValidator 4 | ValidateDescription 5 | Array<InternalFormats | CustomValidator | ValidateDescription>
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
10 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 7/26 approved changesets -- score normalized to 2
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
97 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More