性能
¥Performance
处理大量节点或复杂组件时,性能管理可能具有挑战性。以下是一些优化 React Flow 性能的有效策略。
¥When dealing with a large number of nodes or complex components, managing performance can be challenging. Here are a few effective strategies to optimize the performance of React Flow.
使用 memoization
¥Use memoization
React Flow 中性能问题的主要原因之一是不必要的重新渲染。由于节点移动会触发频繁的状态更新,这可能会导致性能瓶颈,尤其是在较大的图中。
¥One of the main reasons for performance issues in React Flow is unnecessary re-renders. Since node movements trigger frequent state updates, this can lead to performance bottlenecks, especially in larger diagrams.
记忆组件
¥Memoize components
作为 props 提供给 <ReactFlow>
组件的组件(包括自定义节点和边组件),应该使用 React.memo
进行记忆,或在父组件外部声明。这确保 React 不会在每次渲染时都为组件创建新的引用,否则会触发不必要的重新渲染。
¥Components provided as props to the <ReactFlow>
component, including custom node and
edge components, should either be memoized using React.memo
or declared outside the
parent component. This ensures that React does not create a new reference for the
component on every render, which would otherwise trigger unnecessary re-renders.
const NodeComponent = memo(() => {
return <div>{data.label}</div>;
});
记忆函数
¥Memoize functions
同样,作为 props 传递给 <ReactFlow>
的函数应该使用 useCallback
进行记忆。这可防止 React 在每次渲染时都创建新的函数引用,这也可能触发不必要的重新渲染。此外,像 defaultEdgeOptions
或 snapGrid
这样的数组和对象应该使用 useMemo
进行记忆,以避免不必要的重新渲染。
¥Similarly, functions passed as props to <ReactFlow>
should be memoized using
useCallback
. This prevents React from creating a new function reference on every render,
which could also trigger unnecessary re-renders. Additionally, arrays and objects like
defaultEdgeOptions
or snapGrid
should be memoized using useMemo
to prevent
unnecessary re-renders.
import React, { useCallback } from 'react';
const MyDiagram = () => {
const onNodeClick = useCallback((event, node) => {
console.log('Node clicked:', node);
}, []);
return <ReactFlow onNodeClick={onNodeClick} />;
};
export default MyDiagram;
避免访问组件中的节点
¥Avoid accessing nodes in components
React Flow 中最常见的性能陷阱之一是在组件或视口中直接访问 nodes
或 edges
。这些对象在拖动、平移或缩放等操作期间会频繁变化,这可能会导致依赖它们的组件不必要的重新渲染。
¥One of the most common performance pitfalls in React Flow is directly accessing
the nodes
or edges
in the components or the viewport. These objects change frequently
during operations like dragging, panning, or zooming, which can cause unnecessary
re-renders of components that depend on them.
例如,如果你从 store 中获取整个 nodes
数组并对其进行过滤以显示选定的节点 ID,则这种方法可能会导致性能下降。每次更新 nodes
数组都会触发所有依赖组件的重新渲染,即使更改与所选节点无关。
¥For example, if you fetch the entire nodes
array from the store and filter it to display
selected node IDs, this approach can lead to performance degradation. Every update to
the nodes
array triggers a re-render of all dependent components, even if the change is
unrelated to the selected nodes.
低效示例
¥Inefficient example
const SelectedNodeIds = () => {
// ❌ This will cause unnecessary re-renders!
const nodes = useStore((state) => state.nodes);
const selectedNodeIds = nodes.filter((node) => node.selected).map((node) => node.id);
return (
<div>
{selectedNodeIds.map((id) => (
<div key={id}>{id}</div>
))}
</div>
);
};
在此示例中,即使选择内容未发生改变,每次更新 nodes
数组都会导致 SelectedNodeIds
组件重新渲染。
¥In this example, every update to the nodes
array causes the SelectedNodeIds
component
to re-render, even if the selection hasn’t changed.
优化方案
¥Optimized solution
为避免不必要的重新渲染,请将选定的节点存储在状态中的单独字段中(使用 Zustand、Redux 或任何其他状态管理解决方案)。这确保组件仅在选择发生变化时重新渲染。
¥To avoid unnecessary re-renders, store the selected nodes in a separate field in your state (using Zustand, Redux, or any other state management solution). This ensures that the component only re-renders when the selection changes.
const SelectedNodeIds = () => {
const selectedNodeIds = useStore((state) => state.selectedNodeIds);
return (
<div>
{selectedNodeIds.map((id) => (
<div key={id}>{id}</div>
))}
</div>
);
};
通过将选定节点与 nodes
数组解耦,可以避免不必要的更新并提高性能。有关更多信息,请查看我们的 状态管理指南。
¥By decoupling the selected nodes from the nodes
array, you prevent unnecessary updates
and improve performance. For more information, view our
State Management guide.
折叠大型节点树
¥Collapse large node trees
如果你的节点树嵌套很深,一次性渲染所有节点可能会效率低下。而是仅显示有限数量的节点,并允许用户根据需要扩展它们。你可以通过动态修改节点的 hidden
属性来切换可见性。
¥If your node tree is deeply nested, rendering all nodes at once can be inefficient.
Instead, show only a limited number of nodes and allow users to expand them as needed. You
can do this by modifying the node’s hidden
property dynamically to toggle visibility.
const handleNodeClick = (targetNode) => {
if (targetNode.data.children) {
setNodes((prevNodes) =>
prevNodes.map((node) =>
targetNode.data.children.includes(node.id)
? { ...node, hidden: !node.hidden }
: node,
),
);
}
};
通过最初隐藏节点并仅在展开时渲染它们,我们在保持可用性的同时优化了性能。
¥By hiding nodes initially and rendering them only when expanded, we optimize performance while maintaining usability.
简化节点和边缘样式
¥Simplify node and edge styles
如果你已经通过其他所有方式优化了性能,但仍然发现大量节点的性能问题,那么复杂的 CSS 样式(尤其是涉及动画、阴影或渐变的样式)可能会显著影响性能。在这些情况下,请考虑降低节点样式的复杂性。
¥If you’ve optimized performance in every other way, and you are still finding performance issues with large numbers of nodes, complex CSS styles, particularly those involving animations, shadows, or gradients, can significantly impact performance. Consider reducing complexity on your node styles in these cases.
其他资源
¥Additional resources
以下是一些关于 React Flow 性能的有用资源,你可以查看:
¥Here are a few helpful resources on performance in React Flow that you can check out: