性能
🌐 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
作为 <ReactFlow> 组件的 props 提供的组件,包括自定义节点和边组件,应使用 React.memo 进行 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
类似地,传递给 <ReactFlow> 的函数作为 props 应该使用 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.
例如,如果你从存储中获取整个 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: