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)
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { id, type, data, updateData, node } = useNodeRender()
|
||||
}
|
||||
```
|
||||
|
||||
## Creating Nodes
|
||||
|
||||
Create through [FlowOperationService](/api/services/flow-operation-service.html)
|
||||
@ -163,23 +169,19 @@ function BaseNode({ node }) {
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { form } = useNodeRender();
|
||||
// Corresponding node data
|
||||
console.log(form.values)
|
||||
|
||||
// Monitor node data changes
|
||||
useEffect(() => {
|
||||
const toDispose = form.onFormValuesChange(() => {
|
||||
// changed
|
||||
})
|
||||
return () => toDispose.dispose()
|
||||
}, [form])
|
||||
const { data, updateData } = useNodeRender();
|
||||
// Corresponds to node's data
|
||||
console.log(data)
|
||||
|
||||
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
|
||||
|
||||
@ -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)
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { id, type, data, updateData, node } = useNodeRender()
|
||||
}
|
||||
```
|
||||
|
||||
## Create Node
|
||||
|
||||
- Through [WorkflowDocument](/api/core/workflow-document.html)
|
||||
@ -96,23 +102,19 @@ function BaseNode({ node }) {
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { form } = useNodeRender();
|
||||
const { data, updateData } = useNodeRender();
|
||||
// Corresponds to node's data
|
||||
console.log(form.values)
|
||||
|
||||
// Listen to node data changes
|
||||
useEffect(() => {
|
||||
const toDispose = form.onFormValuesChange(() => {
|
||||
// changed
|
||||
})
|
||||
return () => toDispose.dispose()
|
||||
}, [form])
|
||||
console.log(data)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@ -97,6 +97,12 @@ export const nodeRegistries: FlowNodeRegistry[] = [
|
||||
|
||||
通过 [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) 创建
|
||||
@ -164,22 +170,17 @@ function BaseNode({ node }) {
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { form } = useNodeRender();
|
||||
const { data, updateData } = useNodeRender();
|
||||
// 对应节点的 data 数据
|
||||
console.log(form.values)
|
||||
|
||||
// 监听节点的数据变化
|
||||
useEffect(() => {
|
||||
const toDispose = form.onFormValuesChange(() => {
|
||||
// changed
|
||||
})
|
||||
return () => toDispose.dispose()
|
||||
}, [form])
|
||||
console.log(data)
|
||||
|
||||
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)
|
||||
|
||||
@ -37,6 +37,12 @@ const nodeData: FlowNodeJSON = {
|
||||
|
||||
通过 [useNodeRender](api/hooks/use-node-render.html) 获取节点相关方法
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { id, type, data, updateData, node } = useNodeRender()
|
||||
}
|
||||
```
|
||||
|
||||
## 创建节点
|
||||
|
||||
- 通过 [WorkflowDocument](/api/core/workflow-document.html) 创建
|
||||
@ -96,22 +102,17 @@ function BaseNode({ node }) {
|
||||
|
||||
```tsx pure
|
||||
function BaseNode() {
|
||||
const { form } = useNodeRender();
|
||||
const { data, updateData } = useNodeRender();
|
||||
// 对应节点的 data 数据
|
||||
console.log(form.values)
|
||||
|
||||
// 监听节点的数据变化
|
||||
useEffect(() => {
|
||||
const toDispose = form.onFormValuesChange(() => {
|
||||
// changed
|
||||
})
|
||||
return () => toDispose.dispose()
|
||||
}, [form])
|
||||
console.log(data)
|
||||
|
||||
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)
|
||||
|
||||
@ -4,10 +4,20 @@ import { FlowNodeEntity } from '@flowgram.ai/document';
|
||||
import { type WorkflowPortEntity } from '../entities';
|
||||
|
||||
export interface NodeRenderReturnType {
|
||||
id: string;
|
||||
type: string | number;
|
||||
/**
|
||||
* 当前节点
|
||||
*/
|
||||
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')
|
||||
);
|
||||
}
|
||||
|
||||
export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderReturnType {
|
||||
const node = nodeFromProps || useContext<WorkflowNodeEntity>(PlaygroundEntityContext);
|
||||
const renderData = node.getData(FlowNodeRenderData)!;
|
||||
@ -33,6 +34,9 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
||||
const dragService = useService<WorkflowDragService>(WorkflowDragService);
|
||||
const selectionService = useService<WorkflowSelectService>(WorkflowSelectService);
|
||||
const isDragging = useRef(false);
|
||||
const [formValueVersion, updateFormValueVersion] = useState<number>(0);
|
||||
const formValueDependRef = useRef(false);
|
||||
formValueDependRef.current = false;
|
||||
const nodeRef = useRef<HTMLDivElement | null>(null);
|
||||
const [linkingNodeId, setLinkingNodeId] = useState('');
|
||||
|
||||
@ -126,35 +130,85 @@ export function useNodeRender(nodeFromProps?: WorkflowNodeEntity): NodeRenderRet
|
||||
const toggleExpand = useCallback(() => {
|
||||
renderData.toggleExpand();
|
||||
}, [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 {
|
||||
node,
|
||||
selected: selectionService.isSelected(node.id),
|
||||
activated: selectionService.isActivated(node.id),
|
||||
expanded: renderData.expanded,
|
||||
startDrag,
|
||||
ports: portsData.allPorts,
|
||||
deleteNode,
|
||||
selectNode,
|
||||
readonly,
|
||||
linkingNodeId,
|
||||
nodeRef,
|
||||
onFocus,
|
||||
onBlur,
|
||||
getExtInfo,
|
||||
updateExtInfo,
|
||||
toggleExpand,
|
||||
get form() {
|
||||
if (!form) return undefined;
|
||||
return {
|
||||
...form,
|
||||
get values() {
|
||||
return form.values!;
|
||||
},
|
||||
get state() {
|
||||
return formState;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
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,
|
||||
selected,
|
||||
activated,
|
||||
expanded,
|
||||
startDrag,
|
||||
get ports() {
|
||||
return portsData.allPorts;
|
||||
},
|
||||
deleteNode,
|
||||
selectNode,
|
||||
readonly,
|
||||
linkingNodeId,
|
||||
nodeRef,
|
||||
onFocus,
|
||||
onBlur,
|
||||
getExtInfo,
|
||||
updateExtInfo,
|
||||
toggleExpand,
|
||||
get form() {
|
||||
if (!form) return undefined;
|
||||
return {
|
||||
...form,
|
||||
get values() {
|
||||
formValueDependRef.current = true;
|
||||
return form.values!;
|
||||
},
|
||||
get state() {
|
||||
return formState;
|
||||
},
|
||||
};
|
||||
},
|
||||
}),
|
||||
[
|
||||
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 { useStartDragNode } from '@flowgram.ai/fixed-drag-plugin';
|
||||
@ -17,6 +17,16 @@ import {
|
||||
import { FlowOperationService } from '../types';
|
||||
|
||||
export interface NodeRenderReturnType {
|
||||
id: string;
|
||||
type: string | number;
|
||||
/**
|
||||
* 节点 data 数据
|
||||
*/
|
||||
data: any;
|
||||
/**
|
||||
* 更新节点 data 数据
|
||||
*/
|
||||
updateData: (newData: any) => void;
|
||||
/**
|
||||
* BlockOrderIcon节点,一般用于分支的第一个占位节点
|
||||
*/
|
||||
@ -100,6 +110,9 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
||||
const playground = usePlayground();
|
||||
const isBlockOrderIcon = renderNode.flowNodeType === FlowNodeBaseType.BLOCK_ORDER_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 进行缓存
|
||||
const node =
|
||||
(isBlockOrderIcon || isBlockIcon ? renderNode.parent! : renderNode) || nodeCache.current;
|
||||
@ -154,10 +167,35 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
||||
return () => dispose?.dispose();
|
||||
}, [renderNode, isBlockIcon, isBlockOrderIcon]);
|
||||
|
||||
useEffect(() => {
|
||||
const toDispose = form?.onFormValuesChange(() => {
|
||||
if (formValueDependRef.current) {
|
||||
updateFormValueVersion((v) => v + 1);
|
||||
}
|
||||
});
|
||||
return () => toDispose?.dispose();
|
||||
}, [form]);
|
||||
|
||||
const readonly = playground.config.readonly;
|
||||
|
||||
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,
|
||||
isBlockOrderIcon,
|
||||
isBlockIcon,
|
||||
@ -177,6 +215,7 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
||||
return {
|
||||
...form,
|
||||
get values() {
|
||||
formValueDependRef.current = true;
|
||||
return form.values!;
|
||||
},
|
||||
get state() {
|
||||
@ -202,6 +241,7 @@ export function useNodeRender(nodeFromProps?: FlowNodeEntity): NodeRenderReturnT
|
||||
toggleExpand,
|
||||
form,
|
||||
formState,
|
||||
formValueVersion,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user