自定义节点
React Flow 的一项强大功能是能够添加自定义节点。在您的自定义节点中,您可以渲染您想要的任何内容。例如,您可以定义多个源句柄和目标句柄,并渲染表单输入或图表。在本节中,我们将实现一个带有输入字段的节点,该输入字段会更新应用程序其他部分中的某些文本。
实现自定义节点
自定义节点是一个 React 组件,它被包装以提供基本功能,如选择或拖动。从包装组件中,我们传递了诸如位置或数据之类的 props 以及其他 props。让我们开始实现 TextUpdaterNode
。我们使用Handle
组件 来连接我们的自定义节点与其他节点,并在节点中添加输入字段
import { useCallback } from 'react';
import { Handle, Position } from '@xyflow/react';
const handleStyle = { left: 10 };
function TextUpdaterNode({ data }) {
const onChange = useCallback((evt) => {
console.log(evt.target.value);
}, []);
return (
<>
<Handle type="target" position={Position.Top} />
<div>
<label htmlFor="text">Text:</label>
<input id="text" name="text" onChange={onChange} className="nodrag" />
</div>
<Handle type="source" position={Position.Bottom} id="a" />
<Handle
type="source"
position={Position.Bottom}
id="b"
style={handleStyle}
/>
</>
);
}
如您所见,我们在输入中添加了类名“nodrag”。这可以防止在输入字段中拖动,并使我们能够选择文本等。
添加节点类型
您可以通过将新节点类型添加到 nodeTypes
属性来将新节点类型添加到 React Flow。重要的是,nodeTypes
要被记忆化或定义在组件外部。否则,React 会在每次渲染时创建一个新对象,这会导致性能问题和错误。
const nodeTypes = useMemo(() => ({ textUpdater: TextUpdaterNode }), []);
return <ReactFlow nodeTypes={nodeTypes} />;
定义新节点类型后,您可以通过使用 type
节点选项来使用它
const nodes = [
{
id: 'node-1',
type: 'textUpdater',
position: { x: 0, y: 0 },
data: { value: 123 },
},
];
将所有内容组合在一起并添加一些基本样式后,我们得到一个自定义节点,该节点将文本打印到控制台
使用多个句柄
如您所见,我们在节点中添加了两个源句柄,以便它有两个输出。如果您想用这些特定句柄连接其他节点,节点 ID 不够,还需要传递特定的句柄 ID。在这种情况下,一个句柄的 ID 为 "a"
,另一个为 "b"
。句柄特定边使用 sourceHandle
或 targetHandle
选项,它们引用节点中的句柄
const initialEdges = [
{ id: 'edge-1', source: 'node-1', sourceHandle: 'a', target: 'node-2' },
{ id: 'edge-2', source: 'node-1', sourceHandle: 'b', target: 'node-3' },
];
在这种情况下,源节点是 node-1
,这两个句柄都来自它,但句柄 ID 不同。一个来自句柄 ID "a"
,另一个来自 "b"
。这两个边也有不同的目标节点
请注意,如果您在自定义节点中以编程方式更改句柄的位置或数量,则需要使用useUpdateNodeInternals
钩子来正确通知 ReactFlow 更改。从这里,您应该能够构建您的自定义节点。在大多数情况下,我们建议只使用自定义节点。内置节点只是基本示例。您可以在自定义节点 API 部分中找到传递的 props 列表和更多信息。