refactor(elements): simplfy node and edge handling
This commit is contained in:
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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}`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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
@@ -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: [],
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user