--- title: Define Nodes with React order: 13 --- In G6, custom nodes typically require manipulating DOM or Canvas elements, but with the help of the `@antv/g6-extension-react` ecosystem library, you can directly use React components as node content, enhancing development efficiency and maintainability. ## Choosing a Custom Node Solution ### G6 Node ✅ **Recommended Scenarios:** - Nodes are simple geometric shapes - Scenarios requiring efficient rendering of more than 2,000 nodes - Need to directly manipulate graphic instances for fine control > For detailed information on how to customize nodes using Canvas graphics, please refer to the [Custom Node](/en/manual/element/node/custom-node) documentation ### React Node ✅ **Recommended Scenarios:** - Business systems that need to integrate UI libraries like Ant Design - Nodes contain interactive logic such as form input, state switching - Scenarios where an existing React design system needs to be reused ## Quick Start ### Environment Preparation Before starting, please ensure you have: - **Installed a React project**: Ensure a React project is installed and created. - **React version requirement**: Ensure the React version used is >=16.8.0. ### Install Dependencies To use `@antv/g6-extension-react`, run the following command: :::code-group ```bash [npm] npm install @antv/g6-extension-react ``` ```bash [yarn] yarn add @antv/g6-extension-react ``` ```bash [pnpm] pnpm add @antv/g6-extension-react ``` ::: ### Component Integration #### 1. Register React Node Type Register the React node type through the extension mechanism: ```jsx import { ExtensionCategory, register } from '@antv/g6'; import { ReactNode } from '@antv/g6-extension-react'; register(ExtensionCategory.NODE, 'react-node', ReactNode); ``` The `register` method requires three parameters: - Extension category: `ExtensionCategory.NODE` indicates this is a node type - Type name: `react-node` is the name we give to this custom node, which will be used in the configuration later - Class definition: ReactNode is the implementation class exported by `@antv/g6-extension-react` #### 2. Define Business Component Define a simple React component as the content of the node: ```jsx const MyReactNode = () => { return
node
; }; ``` #### 3. Use the Component Use the custom React node in the graph configuration. Specify the node type and style in the graph configuration to use the custom React component. - `type`: Specify the node type as `react-node` (use the name given during registration) - `style.component`: Define the React component content of the node ```jsx const graph = new Graph({ node: { type: 'react-node', style: { component: () => , }, }, }); graph.render(); ``` ## Advanced Features ### State Management In complex graph visualization scenarios, nodes need to dynamically respond to interaction states. We provide two complementary state management solutions: #### Respond to Built-in Interaction States G6 provides built-in interaction state management states, such as `hover-activate` and `click-select`. You can get the current node state through the `data.states` field in the node data and adjust the node style based on the state. **Example**: Change the background color when the node is hovered. ```jsx import { ExtensionCategory, register, Graph } from '@antv/g6'; import { ReactNode } from '@antv/g6-extension-react'; register(ExtensionCategory.NODE, 'react-node', ReactNode); const StatefulNode = ({ data }) => { const isActive = data.states?.includes('active'); return (
{data.data.label}
); }; const graph = new Graph({ data: { nodes: [ { id: 'node1', style: { x: 100, y: 200 }, data: { label: 'node1' } }, { id: 'node2', style: { x: 300, y: 200 }, data: { label: 'node2' } }, ], }, node: { type: 'react-node', style: { component: (data) => , }, }, behaviors: ['hover-activate'], }); graph.render(); ``` #### Custom Business State When you need to manage business-related states (such as approval status, risk level), you can extend node data to achieve this: **Example**: Add a `selected` variable through data to achieve style changes for node selection and deselection. ```jsx import { ExtensionCategory, register, Graph } from '@antv/g6'; import { ReactNode } from '@antv/g6-extension-react'; register(ExtensionCategory.NODE, 'react-node', ReactNode); const MyReactNode = ({ data, graph }) => { const handleClick = () => { graph.updateNodeData([{ id: data.id, data: { selected: !data.data.selected } }]); graph.draw(); }; return (
Node
); }; const graph = new Graph({ data: { nodes: [ { id: 'node1', style: { x: 100, y: 100 }, data: { selected: true }, }, ], }, node: { type: 'react-node', style: { component: (data) => , }, }, }); graph.render(); ``` ### Event Interaction Achieve two-way communication between nodes and graph instances, allowing nodes and graph instances to update each other. **Example**: Operate graph data through custom nodes and re-render the graph. ```jsx const IDCardNode = ({ id, selected, graph }) => { const handleSelect = () => { graph.updateNodeData([{ id, data: { selected: true } }]); graph.draw(); }; return { const url = event.target.value; onChange?.(url); }} /> ); }; export const ReactNodeDemo = () => { const containerRef = useRef(); useEffect(() => { const graph = new Graph({ container: containerRef.current, data: { nodes: [ { id: 'local-server-1', data: { status: 'success', type: 'local', url: 'http://localhost:3000' }, style: { x: 50, y: 50 }, }, { id: 'remote-server-1', data: { status: 'warning', type: 'remote' }, style: { x: 350, y: 50 }, }, ], edges: [{ source: 'local-server-1', target: 'remote-server-1' }], }, node: { type: 'react', style: { size: [240, 100], component: (data) => , }, }, behaviors: ['drag-element', 'zoom-canvas', 'drag-canvas'], }); graph.render(); }, []); return
; }; const root = createRoot(document.getElementById('container')); root.render(); ```
```js | ob { inject: true } import { UserOutlined } from '@ant-design/icons'; import { ExtensionCategory, Graph, register } from '@antv/g6'; import { ReactNode } from '@antv/g6-extension-react'; import { Avatar, Button, Card, Descriptions, Select, Space, Typography } from 'antd'; import React, { useEffect, useRef } from 'react'; import { createRoot } from 'react-dom/client'; const { Title, Text } = Typography; const { Option } = Select; register(ExtensionCategory.NODE, 'react-node', ReactNode); const IDCardNode = ({ id, data }) => { const { name, idNumber, address, expanded, selected, graph } = data; const toggleExpand = (e) => { e.stopPropagation(); graph.updateNodeData([ { id, data: { expanded: !expanded }, }, ]); graph.render(); }; const handleSelect = (value) => { graph.updateNodeData([ { id, data: { selected: value !== 0 }, }, ]); if (value === 2) { // 获取与当前节点相连的所有节点 const connectedNodes = graph.getNeighborNodesData(id); connectedNodes.forEach((node) => { graph.updateNodeData([ { id: node.id, data: { selected: true }, }, ]); }); } graph.render(); }; const CardTitle = (
} /> {name}
); return ( {expanded ? ( {idNumber} {address} ) : ( IDCard Information )} ); }; // 定义 Graph 数据 const data = { nodes: [ { id: 'node1', data: { name: 'Alice', idNumber: 'IDUSAASD2131734', address: '1234 Broadway, Apt 5B, New York, NY 10001', expanded: false, // 初始状态为收缩 selected: false, // 初始状态为未选中 selectedOption: 1, // 初始选择本节点 }, style: { x: 50, y: 50 }, }, { id: 'node2', data: { name: 'Bob', idNumber: 'IDUSAASD1431920', address: '3030 Chestnut St, Philadelphia, PA 19104', expanded: false, // 初始状态为收缩 selected: false, // 初始状态为未选中 selectedOption: 0, // 初始不选择 }, style: { x: 700, y: 100 }, }, { id: 'node3', data: { name: 'Charlie', idNumber: 'IDUSAASD1431921', address: '4040 Elm St, Chicago, IL 60611', expanded: false, selected: true, selectedOption: 0, }, }, { id: 'node4', data: { name: 'David', idNumber: 'IDUSAASD1431922', address: '5050 Oak St, Houston, TX 77002', expanded: false, selected: false, selectedOption: 0, }, }, { id: 'node5', data: { name: 'Eve', idNumber: 'IDUSAASD1431923', address: '6060 Pine St, Phoenix, AZ 85001', expanded: false, selected: false, selectedOption: 0, }, }, ], edges: [ { source: 'node1', target: 'node2' }, { source: 'node2', target: 'node3' }, { source: 'node3', target: 'node4' }, { source: 'node4', target: 'node5' }, ], }; export const ReactNodeDemo = () => { const containerRef = useRef(); const graphRef = useRef(null); useEffect(() => { // 创建 Graph 实例 const graph = new Graph({ autoFit: 'view', container: containerRef.current, data, node: { type: 'react-node', style: { size: (datum) => (datum.data.expanded ? [340, 236] : [340, 105]), // 调整大小以适应内容 component: (data) => , }, }, behaviors: ['drag-element', 'zoom-canvas', 'drag-canvas'], layout: { type: 'snake', cols: 2, rowGap: 100, colGap: 220, }, }); // 渲染 Graph graph.render(); // 保存 graph 实例 graphRef.current = graph; return () => { graph.destroy(); }; }, []); return
; }; // 渲染 React 组件到 DOM const root = createRoot(document.getElementById('container')); root.render(); ```