NodeRenderer: don’t rerender unless visible nodes change

This commit is contained in:
Ivan Akulov
2023-11-25 02:18:57 +01:00
parent 99d945f33c
commit 0473161325
4 changed files with 106 additions and 83 deletions
@@ -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}
+25 -13
View File
@@ -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;