学习自定义 React Flow

自定义节点

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 },
  },
];

将所有内容组合在一起并添加一些基本样式后,我们得到一个自定义节点,该节点将文本打印到控制台

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

只读

使用多个句柄

如您所见,我们在节点中添加了两个源句柄,以便它有两个输出。如果您想用这些特定句柄连接其他节点,节点 ID 不够,还需要传递特定的句柄 ID。在这种情况下,一个句柄的 ID 为 "a",另一个为 "b"。句柄特定边使用 sourceHandletargetHandle 选项,它们引用节点中的句柄

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"。这两个边也有不同的目标节点

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

只读

请注意,如果您在自定义节点中以编程方式更改句柄的位置或数量,则需要使用useUpdateNodeInternals 钩子来正确通知 ReactFlow 更改。从这里,您应该能够构建您的自定义节点。在大多数情况下,我们建议只使用自定义节点。内置节点只是基本示例。您可以在自定义节点 API 部分中找到传递的 props 列表和更多信息。