NodeRenderer: don’t rerender unless visible nodes change
This commit is contained in:
@@ -2,7 +2,7 @@ import { memo, useMemo, useEffect, useRef, type ComponentType } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { internalsSymbol, errorMessages, Position, clampPosition, getPositionWithOrigin } from '@xyflow/system';
|
||||
|
||||
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
||||
import useVisibleNodesIds from '../../hooks/useVisibleNodes';
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
import { containerStyle } from '../../styles/utils';
|
||||
import { GraphViewProps } from '../GraphView';
|
||||
@@ -39,7 +39,7 @@ const selector = (s: ReactFlowState) => ({
|
||||
const NodeRenderer = (props: NodeRendererProps) => {
|
||||
const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, updateNodeDimensions, onError } =
|
||||
useStore(selector, shallow);
|
||||
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
||||
const nodeIds = useVisibleNodesIds(props.onlyRenderVisibleElements);
|
||||
const resizeObserverRef = useRef<ResizeObserver>();
|
||||
|
||||
const resizeObserver = useMemo(() => {
|
||||
@@ -75,11 +75,11 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
|
||||
return (
|
||||
<div className="react-flow__nodes" style={containerStyle}>
|
||||
{nodes.map((node) => {
|
||||
{nodeIds.map((nodeId) => {
|
||||
return (
|
||||
<NodeComponentWrapper
|
||||
key={node.id}
|
||||
id={node.id}
|
||||
key={nodeId}
|
||||
id={nodeId}
|
||||
nodeTypes={props.nodeTypes}
|
||||
nodeExtent={props.nodeExtent}
|
||||
nodeOrigin={props.nodeOrigin}
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
import { useCallback } from 'react';
|
||||
import { getNodesInside } from '@xyflow/system';
|
||||
import { createSelector } from 'reselect';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../hooks/useStore';
|
||||
import type { Node, ReactFlowState } from '../types';
|
||||
|
||||
function useVisibleNodes(onlyRenderVisible: boolean) {
|
||||
const nodes = useStore(
|
||||
useCallback(
|
||||
(s: ReactFlowState) =>
|
||||
onlyRenderVisible
|
||||
? getNodesInside<Node>(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true)
|
||||
: s.nodes,
|
||||
[onlyRenderVisible]
|
||||
)
|
||||
);
|
||||
const visibleNodeIdsSelector = createSelector(
|
||||
[
|
||||
(s: ReactFlowState) => s.nodes,
|
||||
(s: ReactFlowState) => s.width,
|
||||
(s: ReactFlowState) => s.height,
|
||||
(s: ReactFlowState) => s.transform,
|
||||
(_s: ReactFlowState, onlyRenderVisibleNodes: boolean) => onlyRenderVisibleNodes,
|
||||
],
|
||||
(nodes, width, height, transform, onlyRenderVisible) =>
|
||||
onlyRenderVisible
|
||||
? getNodesInside<Node>(nodes, { x: 0, y: 0, width, height }, transform, true).map((node) => node.id)
|
||||
: nodes.map((node) => node.id),
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallow,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return nodes;
|
||||
function useVisibleNodeIds(onlyRenderVisible: boolean) {
|
||||
const nodeIds = useStore((s: ReactFlowState) => visibleNodeIdsSelector(s, onlyRenderVisible));
|
||||
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
export default useVisibleNodes;
|
||||
export default useVisibleNodeIds;
|
||||
|
||||
Reference in New Issue
Block a user