docs/docs/en/flow-engine/quickstart.md
In React, we usually render a button component like this:
import { Button } from 'antd';
export default function App() {
return <Button type="primary">Primary Button</Button>;
}
Although the code above is simple, it's a static component and cannot meet the needs of a no-code platform for configurability and orchestration capabilities.
In NocoBase's FlowEngine, we can quickly build components that support configuration and are event-driven using FlowModel + FlowDefinition, achieving more powerful no-code capabilities.
<code src="./demos/quickstart-1-basic.tsx"></code>
FlowModel is the core component model in FlowEngine, encapsulating component logic, rendering, and configuration capabilities.FlowModel.class MyModel extends FlowModel {
render() {
return <Button {...this.props} />;
}
}
const model = this.flowEngine.createModel({
uid: 'my-model',
use: 'MyModel',
props: {
type: 'primary',
children: 'Primary Button',
},
});
<FlowModelRenderer /><FlowModelRenderer model={model} />
<code src="./demos/quickstart-2-register-propsflow.tsx"></code>
Using Flow instead of static props allows for:
const buttonSettings = defineFlow({
key: 'buttonSettings',
title: 'Button Settings',
steps: {
general: {
title: 'General Configuration',
uiSchema: {
title: {
type: 'string',
title: 'Button Title',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
type: {
type: 'string',
title: 'Type',
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'Primary', value: 'primary' },
{ label: 'Default', value: 'default' },
{ label: 'Danger', value: 'danger' },
{ label: 'Dashed', value: 'dashed' },
{ label: 'Link', value: 'link' },
{ label: 'Text', value: 'text' },
],
},
icon: {
type: 'string',
title: 'Icon',
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'Search', value: 'SearchOutlined' },
{ label: 'Add', value: 'PlusOutlined' },
{ label: 'Delete', value: 'DeleteOutlined' },
{ label: 'Edit', value: 'EditOutlined' },
{ label: 'Settings', value: 'SettingOutlined' },
],
},
},
defaultParams: {
type: 'primary',
},
// Step handler function, sets model properties
handler(ctx, params) {
ctx.model.setProps('children', params.title);
ctx.model.setProps('type', params.type);
ctx.model.setProps('icon', params.icon ? React.createElement(icons[params.icon]) : undefined);
},
},
},
});
MyModel.registerFlow(buttonSettings);
stepParams instead of static propsconst model = this.flowEngine.createModel({
uid: 'my-model',
use: 'MyModel',
- props: {
- type: 'primary',
- children: 'Primary Button',
- },
+ stepParams: {
+ buttonSettings: {
+ general: {
+ title: 'Primary Button',
+ type: 'primary',
+ },
+ },
+ },
});
✅ Using
stepParamsis the recommended approach in FlowEngine, as it avoids issues with non-serializable data (like React components).
- <FlowModelRenderer model={model} />
+ <FlowModelRenderer model={model} showFlowSettings />
<code src="./demos/quickstart-3-register-eventflow.tsx"></code>
Add onClick in a non-intrusive way
const myPropsFlow = defineFlow({
key: 'buttonSettings',
steps: {
general: {
// ... omitted
handler(ctx, params) {
// ... omitted
+ ctx.model.setProps('onClick', (event) => {
+ ctx.model.dispatchEvent('click', { event });
+ });
},
},
},
});
const myEventFlow = defineFlow({
key: 'clickSettings',
on: 'click',
title: 'Button Event',
steps: {
confirm: {
title: 'Confirmation Action Configuration',
uiSchema: {
title: {
type: 'string',
title: 'Dialog Prompt Title',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
content: {
type: 'string',
title: 'Dialog Prompt Content',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
},
},
defaultParams: {
title: 'Confirm Action',
content: 'You clicked the button, are you sure?',
},
async handler(ctx, params) {
// Dialog
const confirmed = await ctx.modal.confirm({
title: params.title,
content: params.content,
});
// Message
await ctx.message.info(`You clicked the button, confirmation result: ${confirmed ? 'Confirmed' : 'Canceled'}`);
},
},
},
});
MyModel.registerFlow(myEventFlow);
Additional Notes:
onClick, onMouseEnter, etc.) to meet complex business requirements.When creating the model, you can configure the default parameters for the event flow via stepParams:
const model = this.flowEngine.createModel({
uid: 'my-model',
use: 'MyModel',
stepParams: {
buttonSettings: {
general: {
title: 'Primary Button',
type: 'primary',
},
},
clickSettings: {
confirm: {
title: 'Confirm Action',
content: 'You clicked the button, are you sure?',
},
},
},
});
Flow does not change how components are implemented. It simply adds support for PropsFlow and EventFlow to a ReactComponent, allowing the component's properties and events to be configured and orchestrated visually.
graph TD
Button[ButtonComponent]
Button --> Props[Props]
Button --> Events[Events]
Props --> title[title]
Props --> type[type]
Props --> icon[icon]
Events --> onClick[onClick]
graph TD
Button[ButtonModel]
Button --> Props[PropsFlow]
Button --> Events[EventFlow]
Props --> title[title]
Props --> type[type]
Props --> icon[icon]
Events --> onClick[onClick]
Through the three steps above, we have completed a button component that supports configuration and event orchestration, with the following advantages:
This pattern is also applicable to any UI component, such as forms, lists, and charts. In NocoBase's FlowEngine, everything is orchestratable.