refactor(nodes): only re render changed nodes

This commit is contained in:
moklick
2019-07-31 17:24:23 +02:00
parent 6e71591cb8
commit 3403203adb
9 changed files with 3950 additions and 3871 deletions
+1903 -1890
View File
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -18,6 +18,8 @@ const SpecialNode = ({ data, styles }) => (
</div> </div>
); );
const onNodeDragStop = node => console.log('drag stop', node);
class App extends PureComponent { class App extends PureComponent {
constructor() { constructor() {
super(); super();
@@ -58,6 +60,9 @@ class App extends PureComponent {
{ source: '6', target: '7', style: { stroke: '#FFCC00' }}, { source: '6', target: '7', style: { stroke: '#FFCC00' }},
] ]
}; };
this.onElementClick = this.onElementClick.bind(this);
this.onConnect = this.onConnect.bind(this);
} }
onLoad(graphInstance) { onLoad(graphInstance) {
@@ -123,10 +128,10 @@ class App extends PureComponent {
return ( return (
<Graph <Graph
elements={this.state.elements} elements={this.state.elements}
onElementClick={element => this.onElementClick(element)} onElementClick={this.onElementClick}
onElementsRemove={elements => this.onElementsRemove(elements)} onElementsRemove={elements => this.onElementsRemove(elements)}
onConnect={params => this.onConnect(params)} onConnect={this.onConnect}
onNodeDragStop={node => console.log('drag stop', node)} onNodeDragStop={onNodeDragStop}
style={{ width: '100%', height: '100%' }} style={{ width: '100%', height: '100%' }}
onLoad={graphInstance => this.onLoad(graphInstance)} onLoad={graphInstance => this.onLoad(graphInstance)}
onChange={(elements) => this.onChange(elements)} onChange={(elements) => this.onChange(elements)}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+8 -1
View File
@@ -6,7 +6,8 @@ import { isEdge } from '../../graph-utils';
const isInput = e => ['INPUT', 'SELECT', 'TEXTAREA'].includes(e.target.nodeName); const isInput = e => ['INPUT', 'SELECT', 'TEXTAREA'].includes(e.target.nodeName);
export default EdgeComponent => memo((props) => { export default EdgeComponent => {
const WrappedEdge = memo((props) => {
const { const {
source, target, animated, type, source, target, animated, type,
dispatch, selectedElements, onClick dispatch, selectedElements, onClick
@@ -32,3 +33,9 @@ export default EdgeComponent => memo((props) => {
</g> </g>
); );
}); });
WrappedEdge.displayName = 'Wrapped Edge';
WrappedEdge.whyDidYouRender = false;
return WrappedEdge;
};
+4 -1
View File
@@ -20,9 +20,12 @@ export const Provider = (props) => {
const existingNode = state.nodes.find(n => n.id === propNode.id); const existingNode = state.nodes.find(n => n.id === propNode.id);
if (existingNode) { if (existingNode) {
const data = !isEqual(existingNode.data, propNode.data) ?
{ ...existingNode.data, ...propNode.data } : existingNode.data;
return { return {
...existingNode, ...existingNode,
data: { ...existingNode.data, ...propNode.data } data
}; };
} }
+9 -5
View File
@@ -76,7 +76,8 @@ const onStop = ({ onNodeDragStop, id, type, position, data }) => {
}); });
}; };
export default NodeComponent => memo((props) => { export default NodeComponent => {
const WrappedComp = memo((props) => {
const nodeElement = useRef(null); const nodeElement = useRef(null);
const [offset, setOffset] = useState({ x: 0, y: 0 }); const [offset, setOffset] = useState({ x: 0, y: 0 });
const { const {
@@ -84,8 +85,6 @@ export default NodeComponent => memo((props) => {
dispatch, getNodeById, onClick, onNodeDragStop dispatch, getNodeById, onClick, onNodeDragStop
} = props; } = props;
console.log('render node', id);
const position = { x: xPos, y: yPos }; const position = { x: xPos, y: yPos };
const [ x, y, k ] = transform; const [ x, y, k ] = transform;
const selected = selectedElements.filter(isNode).map(e => e.id).includes(id); const selected = selectedElements.filter(isNode).map(e => e.id).includes(id);
@@ -123,5 +122,10 @@ export default NodeComponent => memo((props) => {
</div> </div>
</ReactDraggable.DraggableCore> </ReactDraggable.DraggableCore>
); );
} });
);
WrappedComp.displayName = 'Wrapped Node';
WrappedComp.whyDidYouRender = false;
return WrappedComp;
};
+29 -9
View File
@@ -1,11 +1,12 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import isEqual from 'lodash.isequal';
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
const whyDidYouRender = require('@welldone-software/why-did-you-render'); const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React); whyDidYouRender(React);
} }
import { parseElements, separateElements } from '../graph-utils'; import { parseElements, isNode, isEdge } from '../graph-utils';
import GraphView from '../GraphView'; import GraphView from '../GraphView';
import GlobalKeyHandler from '../GlobalKeyHandler'; import GlobalKeyHandler from '../GlobalKeyHandler';
import { Provider } from '../GraphContext'; import { Provider } from '../GraphContext';
@@ -27,23 +28,42 @@ class ReactGraph extends PureComponent {
this.nodeTypes = createNodeTypes(props.nodeTypes); this.nodeTypes = createNodeTypes(props.nodeTypes);
this.edgeTypes = createEdgeTypes(props.edgeTypes); this.edgeTypes = createEdgeTypes(props.edgeTypes);
this.state = {
nodes: [],
edges: []
};
}
componentDidMount() {
this.updateElements(this.props.elements);
}
componentDidUpdate(prevProps) {
if (!isEqual(prevProps.elements, this.props.elements)) {
this.updateElements(this.props.elements);
}
}
updateElements(elements) {
const parsedElements = elements.map(parseElements);
this.setState({
nodes: parsedElements.filter(isNode),
edges: parsedElements.filter(isEdge),
});
} }
render() { render() {
const { const {
style, onElementClick, children, onLoad, style, onElementClick, children, onLoad,
onMove, onChange, elements, onElementsRemove, onMove, onChange, onElementsRemove, onConnect, onNodeDragStop,
onConnect, onNodeDragStop, connectionLineType, connectionLineType, connectionLineStyle
connectionLineStyle
} = this.props; } = this.props;
const { nodes, edges } = elements
.map(parseElements)
.reduce(separateElements, {});
return ( return (
<div style={style} className="react-graph"> <div style={style} className="react-graph">
<Provider nodes={nodes} edges={edges} onConnect={onConnect}> <Provider nodes={this.state.nodes} edges={this.state.edges} onConnect={onConnect}>
<GraphView <GraphView
onLoad={onLoad} onLoad={onLoad}
onMove={onMove} onMove={onMove}
+8 -8
View File
@@ -27,7 +27,7 @@ let internalNodeId = 0;
const getId = () => internalNodeId++; const getId = () => internalNodeId++;
export const parseElements = e => { export const parseElements = (e) => {
e.type = e.type || 'default'; e.type = e.type || 'default';
e.id = e.id ? e.id : getId(); e.id = e.id ? e.id : getId();
@@ -35,15 +35,15 @@ export const parseElements = e => {
return e; return e;
} }
return { e.id = e.id.toString();
...e, e.__rg = {
id: e.id.toString(),
__rg: {
position: e.position, position: e.position,
width: null, width: null,
height: null height: null,
} handleBounds : {}
} };
return { ...e };
}; };
export const separateElements = (res, element) => { export const separateElements = (res, element) => {