mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
feat: use-node-render add id,type,data,updateData (#384)
This commit is contained in:
parent
77d8a893cb
commit
3dda7cfdf3
@ -96,6 +96,12 @@ export const nodeRegistries: FlowNodeRegistry[] = [
|
|||||||
|
|
||||||
Get node-related methods through [useNodeRender](/api/hooks/use-node-render.html)
|
Get node-related methods through [useNodeRender](/api/hooks/use-node-render.html)
|
||||||
|
|
||||||
|
```tsx pure
|
||||||
|
function BaseNode() {
|
||||||
|
const { id, type, data, updateData, node } = useNodeRender()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Creating Nodes
|
## Creating Nodes
|
||||||
|
|
||||||
Create through [FlowOperationService](/api/services/flow-operation-service.html)
|
Create through [FlowOperationService](/api/services/flow-operation-service.html)
|
||||||
@ -163,23 +169,19 @@ function BaseNode({ node }) {
|
|||||||
|
|
||||||
```tsx pure
|
```tsx pure
|
||||||
function BaseNode() {
|
function BaseNode() {
|
||||||
const { form } = useNodeRender();
|
const { data, updateData } = useNodeRender();
|
||||||
// Corresponding node data
|
// Corresponds to node's data
|
||||||
console.log(form.values)
|
console.log(data)
|
||||||
|
|
||||||
// Monitor node data changes
|
|
||||||
useEffect(() => {
|
|
||||||
const toDispose = form.onFormValuesChange(() => {
|
|
||||||
// changed
|
|
||||||
})
|
|
||||||
return () => toDispose.dispose()
|
|
||||||
}, [form])
|
|
||||||
|
|
||||||
function onChange(e) {
|
function onChange(e) {
|
||||||
form.setValueIn('title', e.target.value)
|
updateData({
|
||||||
|
...data,
|
||||||
|
title: e.target.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return <input value={form.getValueIn('title')} onChange={onChange}/>
|
return <input value={data.title} onChange={onChange}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- Update form data through Field, see [Form Usage](/guide/advanced/form.html) for details
|
- Update form data through Field, see [Form Usage](/guide/advanced/form.html) for details
|
||||||
|
|||||||
@ -36,6 +36,12 @@ In free layout scenarios, node definition is used to declare node's initial posi
|
|||||||
|
|
||||||
Get node-related methods through [useNodeRender](api/hooks/use-node-render.html)
|
Get node-related methods through [useNodeRender](api/hooks/use-node-render.html)
|
||||||
|
|
||||||
|
```tsx pure
|
||||||
|
function BaseNode() {
|
||||||
|
const { id, type, data, updateData, node } = useNodeRender()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Create Node
|
## Create Node
|
||||||
|
|
||||||
- Through [WorkflowDocument](/api/core/workflow-document.html)
|
- Through [WorkflowDocument](/api/core/workflow-document.html)
|
||||||
@ -96,23 +102,19 @@ function BaseNode({ node }) {
|
|||||||
|
|
||||||
```tsx pure
|
```tsx pure
|
||||||
function BaseNode() {
|
function BaseNode() {
|
||||||
const { form } = useNodeRender();
|
const { data, updateData } = useNodeRender();
|
||||||
// Corresponds to node's data
|
// Corresponds to node's data
|
||||||
console.log(form.values)
|
console.log(data)
|
||||||
|
|
||||||
// Listen to node data changes
|
|
||||||
useEffect(() => {
|
|
||||||
const toDispose = form.onFormValuesChange(() => {
|
|
||||||
// changed
|
|
||||||
})
|
|
||||||
return () => toDispose.dispose()
|
|
||||||
}, [form])
|
|
||||||
|
|
||||||
function onChange(e) {
|
function onChange(e) {
|
||||||
form.setValueIn('title', e.target.value)
|
updateData({
|
||||||
|
...data,
|
||||||
|
title: e.target.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return <input value={form.getValueIn('title')} onChange={onChange}/>
|
return <input value={data.title} onChange={onChange}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
- Update form data through Field, see details in [Form Usage](/guide/advanced/form.html)
|
- Update form data through Field, see details in [Form Usage](/guide/advanced/form.html)
|
||||||
|
|
||||||
|
|||||||
@ -97,6 +97,12 @@ export const nodeRegistries: FlowNodeRegistry[] = [
|
|||||||
|
|
||||||
通过 [useNodeRender](/api/hooks/use-node-render.html) 获取节点相关方法
|
通过 [useNodeRender](/api/hooks/use-node-render.html) 获取节点相关方法
|
||||||
|
|
||||||
|
```tsx pure
|
||||||
|
function BaseNode() {
|
||||||
|
const { id, type, data, updateData, node } = useNodeRender()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 创建节点
|
## 创建节点
|
||||||
|
|
||||||
通过 [FlowOperationService](/api/services/flow-operation-service.html) 创建
|
通过 [FlowOperationService](/api/services/flow-operation-service.html) 创建
|
||||||
@ -164,22 +170,17 @@ function BaseNode({ node }) {
|
|||||||
|
|
||||||
```tsx pure
|
```tsx pure
|
||||||
function BaseNode() {
|
function BaseNode() {
|
||||||
const { form } = useNodeRender();
|
const { data, updateData } = useNodeRender();
|
||||||
// 对应节点的 data 数据
|
// 对应节点的 data 数据
|
||||||
console.log(form.values)
|
console.log(data)
|
||||||
|
|
||||||
// 监听节点的数据变化
|
|
||||||
useEffect(() => {
|
|
||||||
const toDispose = form.onFormValuesChange(() => {
|
|
||||||
// changed
|
|
||||||
})
|
|
||||||
return () => toDispose.dispose()
|
|
||||||
}, [form])
|
|
||||||
|
|
||||||
function onChange(e) {
|
function onChange(e) {
|
||||||
form.setValueIn('title', e.target.value)
|
updateData({
|
||||||
|
...data,
|
||||||
|
title: e.target.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return <input value={form.getValueIn('title')} onChange={onChange}/>
|
return <input value={data.title} onChange={onChange}/>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- 通过 Field 更新表单数据, 详细见 [表单的使用](/guide/advanced/form.html)
|
- 通过 Field 更新表单数据, 详细见 [表单的使用](/guide/advanced/form.html)
|
||||||
|
|||||||
@ -37,6 +37,12 @@ const nodeData: FlowNodeJSON = {
|
|||||||
|
|
||||||
通过 [useNodeRender](api/hooks/use-node-render.html) 获取节点相关方法
|
通过 [useNodeRender](api/hooks/use-node-render.html) 获取节点相关方法
|
||||||
|
|
||||||
|
```tsx pure
|
||||||
|
function BaseNode() {
|
||||||
|
const { id, type, data, updateData, node } = useNodeRender()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 创建节点
|
## 创建节点
|
||||||
|
|
||||||
- 通过 [WorkflowDocument](/api/core/workflow-document.html) 创建
|
- 通过 [WorkflowDocument](/api/core/workflow-document.html) 创建
|
||||||
@ -96,22 +102,17 @@ function BaseNode({ node }) {
|
|||||||
|
|
||||||
```tsx pure
|
```tsx pure
|
||||||
function BaseNode() {
|
function BaseNode() {
|
||||||
const { form } = useNodeRender();
|
const { data, updateData } = useNodeRender();
|
||||||
// 对应节点的 data 数据
|
// 对应节点的 data 数据
|
||||||
console.log(form.values)
|
console.log(data)
|
||||||
|
|
||||||
// 监听节点的数据变化
|
|
||||||
useEffect(() => {
|
|
||||||
const toDispose = form.onFormValuesChange(() => {
|
|
||||||
// changed
|
|
||||||
})
|
|
||||||
return () => toDispose.dispose()
|
|
||||||
}, [form])
|
|
||||||
|
|
||||||
function onChange(e) {
|
function onChange(e) {
|
||||||
form.setValueIn('title', e.target.value)
|
updateData({
|
||||||
|
...data,
|
||||||
|
title: e.target.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return <input value={form.getValueIn('title')} onChange={onChange}/>
|
return <input value={data.title} onChange={onChange}/>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- 通过 Field 更新表单数据, 详细见 [表单的使用](/guide/advanced/form.html)
|
- 通过 Field 更新表单数据, 详细见 [表单的使用](/guide/advanced/form.html)
|
||||||
|
|||||||
@ -4,10 +4,20 @@ import { FlowNodeEntity } from '@flowgram.ai/document';
|
|||||||
import { type WorkflowPortEntity } from '../entities';
|
import { type WorkflowPortEntity } from '../entities';
|
||||||
|
|
||||||
export interface NodeRenderReturnType {
|
export interface NodeRenderReturnType {
|
||||||
|
id: string;
|
||||||
|
type: string | number;
|
||||||
/**
|
/**
|
||||||
* 当前节点
|
* 当前节点
|
||||||
*/
|
*/
|
||||||
node: FlowNodeEntity;
|
node: FlowNodeEntity;
|
||||||
|
/**
|
||||||
|
* 节点 data 数据
|
||||||
|
*/
|
||||||
|
data: any;
|
||||||
|
/**
|
||||||
|
* 更新节点 data 数据
|
||||||
|
*/
|
||||||
|
updateData: (newData: any) => void;
|
||||||
/**
|
/**
|
||||||
* 节点选中
|
* 节点选中
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -25,6 +25,7 @@ function checkTargetDraggable(el: any): boolean {
|
|||||||
!el.closest('.flow-canvas-not-draggable')
|
!el.closest('.flow-canvas-not-draggable')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderReturnType {
|
export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderReturnType {
|
||||||
const node = nodeFromProps || useContext<WorkflowNodeEntity>(PlaygroundEntityContext);
|
const node = nodeFromProps || useContext<WorkflowNodeEntity>(PlaygroundEntityContext);
|
||||||
const renderData = node.getData(FlowNodeRenderData)!;
|
const renderData = node.getData(FlowNodeRenderData)!;
|
||||||
@ -33,6 +34,9 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
|||||||
const dragService = useService<WorkflowDragService>(WorkflowDragService);
|
const dragService = useService<WorkflowDragService>(WorkflowDragService);
|
||||||
const selectionService = useService<WorkflowSelectService>(WorkflowSelectService);
|
const selectionService = useService<WorkflowSelectService>(WorkflowSelectService);
|
||||||
const isDragging = useRef(false);
|
const isDragging = useRef(false);
|
||||||
|
const [formValueVersion, updateFormValueVersion] = useState<number>(0);
|
||||||
|
const formValueDependRef = useRef(false);
|
||||||
|
formValueDependRef.current = false;
|
||||||
const nodeRef = useRef<HTMLDivElement | null>(null);
|
const nodeRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [linkingNodeId, setLinkingNodeId] = useState('');
|
const [linkingNodeId, setLinkingNodeId] = useState('');
|
||||||
|
|
||||||
@ -126,14 +130,44 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
|||||||
const toggleExpand = useCallback(() => {
|
const toggleExpand = useCallback(() => {
|
||||||
renderData.toggleExpand();
|
renderData.toggleExpand();
|
||||||
}, [renderData]);
|
}, [renderData]);
|
||||||
|
const selected = selectionService.isSelected(node.id);
|
||||||
|
const activated = selectionService.isActivated(node.id);
|
||||||
|
const expanded = renderData.expanded;
|
||||||
|
useEffect(() => {
|
||||||
|
const toDispose = form?.onFormValuesChange(() => {
|
||||||
|
if (formValueDependRef.current) {
|
||||||
|
updateFormValueVersion((v) => v + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => toDispose?.dispose();
|
||||||
|
}, [form]);
|
||||||
|
|
||||||
return {
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
id: node.id,
|
||||||
|
type: node.flowNodeType,
|
||||||
|
get data() {
|
||||||
|
if (form) {
|
||||||
|
formValueDependRef.current = true;
|
||||||
|
return form.values;
|
||||||
|
}
|
||||||
|
return getExtInfo();
|
||||||
|
},
|
||||||
|
updateData(values: any) {
|
||||||
|
if (form) {
|
||||||
|
form.updateFormValues(values);
|
||||||
|
} else {
|
||||||
|
updateExtInfo(values);
|
||||||
|
}
|
||||||
|
},
|
||||||
node,
|
node,
|
||||||
selected: selectionService.isSelected(node.id),
|
selected,
|
||||||
activated: selectionService.isActivated(node.id),
|
activated,
|
||||||
expanded: renderData.expanded,
|
expanded,
|
||||||
startDrag,
|
startDrag,
|
||||||
ports: portsData.allPorts,
|
get ports() {
|
||||||
|
return portsData.allPorts;
|
||||||
|
},
|
||||||
deleteNode,
|
deleteNode,
|
||||||
selectNode,
|
selectNode,
|
||||||
readonly,
|
readonly,
|
||||||
@ -149,6 +183,7 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
|||||||
return {
|
return {
|
||||||
...form,
|
...form,
|
||||||
get values() {
|
get values() {
|
||||||
|
formValueDependRef.current = true;
|
||||||
return form.values!;
|
return form.values!;
|
||||||
},
|
},
|
||||||
get state() {
|
get state() {
|
||||||
@ -156,5 +191,24 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
}),
|
||||||
|
[
|
||||||
|
node,
|
||||||
|
selected,
|
||||||
|
activated,
|
||||||
|
expanded,
|
||||||
|
startDrag,
|
||||||
|
deleteNode,
|
||||||
|
selectNode,
|
||||||
|
readonly,
|
||||||
|
linkingNodeId,
|
||||||
|
nodeRef,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
getExtInfo,
|
||||||
|
updateExtInfo,
|
||||||
|
toggleExpand,
|
||||||
|
formValueVersion,
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useContext, useMemo, useRef } from 'react';
|
import React, { useCallback, useEffect, useContext, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useObserve } from '@flowgram.ai/reactive';
|
import { useObserve } from '@flowgram.ai/reactive';
|
||||||
import { useStartDragNode } from '@flowgram.ai/fixed-drag-plugin';
|
import { useStartDragNode } from '@flowgram.ai/fixed-drag-plugin';
|
||||||
@ -17,6 +17,16 @@ import {
|
|||||||
import { FlowOperationService } from '../types';
|
import { FlowOperationService } from '../types';
|
||||||
|
|
||||||
export interface NodeRenderReturnType {
|
export interface NodeRenderReturnType {
|
||||||
|
id: string;
|
||||||
|
type: string | number;
|
||||||
|
/**
|
||||||
|
* 节点 data 数据
|
||||||
|
*/
|
||||||
|
data: any;
|
||||||
|
/**
|
||||||
|
* 更新节点 data 数据
|
||||||
|
*/
|
||||||
|
updateData: (newData: any) => void;
|
||||||
/**
|
/**
|
||||||
* BlockOrderIcon节点,一般用于分支的第一个占位节点
|
* BlockOrderIcon节点,一般用于分支的第一个占位节点
|
||||||
*/
|
*/
|
||||||
@ -100,6 +110,9 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
|||||||
const playground = usePlayground();
|
const playground = usePlayground();
|
||||||
const isBlockOrderIcon = renderNode.flowNodeType === FlowNodeBaseType.BLOCK_ORDER_ICON;
|
const isBlockOrderIcon = renderNode.flowNodeType === FlowNodeBaseType.BLOCK_ORDER_ICON;
|
||||||
const isBlockIcon = renderNode.flowNodeType === FlowNodeBaseType.BLOCK_ICON;
|
const isBlockIcon = renderNode.flowNodeType === FlowNodeBaseType.BLOCK_ICON;
|
||||||
|
const [formValueVersion, updateFormValueVersion] = useState<number>(0);
|
||||||
|
const formValueDependRef = useRef(false);
|
||||||
|
formValueDependRef.current = false;
|
||||||
// 在 BlockIcon 情况,如果在触发 fromJSON 时候更新表单数据导致刷新节点会存在 renderNode.parent 为 undefined,所以这里 nodeCache 进行缓存
|
// 在 BlockIcon 情况,如果在触发 fromJSON 时候更新表单数据导致刷新节点会存在 renderNode.parent 为 undefined,所以这里 nodeCache 进行缓存
|
||||||
const node =
|
const node =
|
||||||
(isBlockOrderIcon || isBlockIcon ? renderNode.parent! : renderNode) || nodeCache.current;
|
(isBlockOrderIcon || isBlockIcon ? renderNode.parent! : renderNode) || nodeCache.current;
|
||||||
@ -154,10 +167,35 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
|||||||
return () => dispose?.dispose();
|
return () => dispose?.dispose();
|
||||||
}, [renderNode, isBlockIcon, isBlockOrderIcon]);
|
}, [renderNode, isBlockIcon, isBlockOrderIcon]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const toDispose = form?.onFormValuesChange(() => {
|
||||||
|
if (formValueDependRef.current) {
|
||||||
|
updateFormValueVersion((v) => v + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => toDispose?.dispose();
|
||||||
|
}, [form]);
|
||||||
|
|
||||||
const readonly = playground.config.readonly;
|
const readonly = playground.config.readonly;
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
id: node.id,
|
||||||
|
type: node.flowNodeType,
|
||||||
|
get data() {
|
||||||
|
if (form) {
|
||||||
|
formValueDependRef.current = true;
|
||||||
|
return form.values;
|
||||||
|
}
|
||||||
|
return getExtInfo();
|
||||||
|
},
|
||||||
|
updateData(values: any) {
|
||||||
|
if (form) {
|
||||||
|
form.updateFormValues(values);
|
||||||
|
} else {
|
||||||
|
updateExtInfo(values);
|
||||||
|
}
|
||||||
|
},
|
||||||
node,
|
node,
|
||||||
isBlockOrderIcon,
|
isBlockOrderIcon,
|
||||||
isBlockIcon,
|
isBlockIcon,
|
||||||
@ -177,6 +215,7 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
|||||||
return {
|
return {
|
||||||
...form,
|
...form,
|
||||||
get values() {
|
get values() {
|
||||||
|
formValueDependRef.current = true;
|
||||||
return form.values!;
|
return form.values!;
|
||||||
},
|
},
|
||||||
get state() {
|
get state() {
|
||||||
@ -202,6 +241,7 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
|||||||
toggleExpand,
|
toggleExpand,
|
||||||
form,
|
form,
|
||||||
formState,
|
formState,
|
||||||
|
formValueVersion,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user