refactor(elements): simplfy node and edge handling

This commit is contained in:
moklick
2019-07-31 18:01:15 +02:00
parent 3403203adb
commit e348cccc76
14 changed files with 4105 additions and 4157 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
import React from 'react';
import React, { memo } from 'react';
export default (props) => {
export default memo((props) => {
const { targetNode, sourceNode } = props;
const style = props.style || {};
@@ -26,4 +26,4 @@ export default (props) => {
d={dAttr}
/>
);
};
});
+3 -3
View File
@@ -1,6 +1,6 @@
import React from 'react';
import React, { memo } from 'react';
export default (props) => {
export default memo((props) => {
const { targetNode, sourceNode } = props;
const style = props.style || {};
@@ -20,4 +20,4 @@ export default (props) => {
d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`}
/>
);
};
});
+1
View File
@@ -21,6 +21,7 @@ function renderEdge(e, props, graphContext) {
return (
<EdgeComponent
key={`${e.source}-${e.target}`}
id={e.id}
type={e.type}
sourceNode={sourceNode}
targetNode={targetNode}
+12 -10
View File
@@ -1,14 +1,16 @@
import React, { createContext, useEffect, useReducer, useRef } from 'react';
import React, { createContext, useEffect, useReducer } from 'react';
import PropTypes from 'prop-types';
import isEqual from 'lodash.isequal';
import { reducer, initialState } from '../state';
import { setNodes, setEdges } from '../state/actions';
import { parseElement, isNode, isEdge } from '../graph-utils';
export const GraphContext = createContext({});
export const Provider = (props) => {
const {
elements,
children,
onConnect
} = props;
@@ -16,7 +18,10 @@ export const Provider = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
const nextNodes = props.nodes.map(propNode => {
const nodes = elements.filter(isNode);
const edges = elements.filter(isEdge).map(parseElement);
const nextNodes = nodes.map(propNode => {
const existingNode = state.nodes.find(n => n.id === propNode.id);
if (existingNode) {
@@ -29,22 +34,21 @@ export const Provider = (props) => {
};
}
return propNode;
return parseElement(propNode);
});
const nodesChanged = !isEqual(state.nodes, nextNodes);
const edgesChanged = !isEqual(state.edges, props.edges);
const edgesChanged = !isEqual(state.edges, edges);
if (nodesChanged) {
dispatch(setNodes(nextNodes));
}
if (edgesChanged) {
dispatch(setEdges(props.edges));
dispatch(setEdges(edges));
}
});
const graphContext = {
state,
dispatch,
@@ -63,11 +67,9 @@ export const Provider = (props) => {
export const { Consumer } = GraphContext;
Provider.propTypes = {
nodes: PropTypes.arrayOf(PropTypes.object),
edges: PropTypes.arrayOf(PropTypes.object)
elements: PropTypes.arrayOf(PropTypes.object)
};
Provider.defaultProps = {
nodes: [],
edges: []
elements: [],
};
+1 -1
View File
@@ -66,7 +66,7 @@ const onNodeClick = (evt, { onClick, dispatch, id, type, position, data }) => {
const node = { id, type, position, data }
dispatch(setSelectedElements(node));
dispatch(setSelectedElements({ id, type }));
onClick(node);
};
+1
View File
@@ -25,6 +25,7 @@ function renderNode(d, props, graphContext) {
transform={graphContext.state.transform}
getNodeById={graphContext.getNodeById}
selectedElements={graphContext.state.selectedElements}
style={d.style}
/>
);
}
+2 -28
View File
@@ -1,12 +1,10 @@
import React, { PureComponent } from 'react';
import isEqual from 'lodash.isequal';
if (process.env.NODE_ENV !== 'production') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React);
}
import { parseElements, isNode, isEdge } from '../graph-utils';
import GraphView from '../GraphView';
import GlobalKeyHandler from '../GlobalKeyHandler';
import { Provider } from '../GraphContext';
@@ -28,42 +26,18 @@ class ReactGraph extends PureComponent {
this.nodeTypes = createNodeTypes(props.nodeTypes);
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() {
const {
style, onElementClick, children, onLoad,
style, onElementClick, elements, children, onLoad,
onMove, onChange, onElementsRemove, onConnect, onNodeDragStop,
connectionLineType, connectionLineStyle
} = this.props;
return (
<div style={style} className="react-graph">
<Provider nodes={this.state.nodes} edges={this.state.edges} onConnect={onConnect}>
<Provider elements={elements} onConnect={onConnect}>
<GraphView
onLoad={onLoad}
onMove={onMove}
+5 -6
View File
@@ -23,15 +23,13 @@ export const removeElements = (elements, elementsToRemove) => {
});
};
let internalNodeId = 0;
const getEdgeId = (e) => `react-graph__edge-${e.source}-${e.target}`;
const getId = () => internalNodeId++;
export const parseElements = (e) => {
export const parseElement = (e) => {
e.type = e.type || 'default';
e.id = e.id ? e.id : getId();
if (isEdge(e)) {
e.id = e.id ? e.id.toString() : getEdgeId(e);
return e;
}
@@ -132,5 +130,6 @@ export default {
separateElements,
getBoundingBox,
graphPosToZoomedPos,
getConnectedEdges
getConnectedEdges,
parseElement
};
+1 -1
View File
@@ -5,7 +5,7 @@ export default ReactGraph;
export { default as SourceHandle } from './NodeRenderer/HandleTypes/SourceHandle';
export { default as TargetHandle } from './NodeRenderer/HandleTypes/TargetHandle';
export {
export {
isNode,
isEdge,
removeElements,
+5 -1
View File
@@ -1,4 +1,5 @@
import { zoomIdentity } from 'd3-zoom';
import isEqual from 'lodash.isequal';
import { getBoundingBox, getNodesInside, getConnectedEdges } from '../graph-utils';
@@ -101,10 +102,13 @@ export const reducer = (state, action) => {
const selectedNodes = getNodesInside(state.nodes, action.payload.selection, state.transform);
const selectedEdges = getConnectedEdges(selectedNodes, state.edges);
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
const selectedElementsUpdated = !isEqual(nextSelectedElements, state.selectedElements);
return {
...state,
...action.payload,
selectedElements: [...selectedNodes, ...selectedEdges]
selectedElements: selectedElementsUpdated ? nextSelectedElements: state.selectedElements
};
}
case SET_NODES_SELECTION: {