Skip to content

Commit

Permalink
refactor(nodeRenderer): dont use Context in nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
moklick committed Jul 31, 2019
1 parent a0646a3 commit ec7231e
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 181 deletions.
6 changes: 3 additions & 3 deletions example/SimpleGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import React, { PureComponent } from 'react';
import Graph, { isEdge, removeElements, getOutgoers, SourceHandle, TargetHandle } from '../src';
// import Graph from '../dist/ReactGraph';

const SpecialNode = ({ data, onChange, styles }) => (
const SpecialNode = ({ data, styles }) => (
<div
style={{ background: '#FFCC00', padding: 10, borderRadius: 2, ...styles }}
>
<TargetHandle style={{ left: 10, background: '#999' }} />
<div>I am <strong>special</strong>!<br />{data.label}</div>
<select onChange={(e) => onChange(e.target.value, data)}>
<select onChange={(e) => data.onChange(e.target.value, data)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
Expand Down Expand Up @@ -48,7 +48,7 @@ class App extends PureComponent {
{ id: '3', data: { label: '3 I bring my own style' }, position: { x: 100, y: 200 }, style: { background: '#eee', color: '#222', border: '1px solid #bbb' } },
{ id: '4', type: 'output', data: { label: '4 nody nodes' }, position: { x: 50, y: 300 } },
{ id: '5', type: 'default', data: { label: '5 Another node'}, position: { x: 400, y: 300 } },
{ id: '6', type: 'special', onChange, data: { label: '6 no option selected' }, position: { x: 425, y: 375 } },
{ id: '6', type: 'special', data: { onChange, label: '6 no option selected' }, position: { x: 425, y: 375 } },
{ id: '7', type: 'output', data: { label: '7 output' }, position: { x: 250, y: 500 } },
{ source: '1', target: '2', animated: true },
{ source: '2', target: '3' },
Expand Down
220 changes: 105 additions & 115 deletions example/build/example.e31bb0bc.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example/build/example.e31bb0bc.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example/build/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"main": "dist/ReactGraph.js",
"private": true,
"dependencies": {
"@welldone-software/why-did-you-render": "^3.2.3",
"classnames": "^2.2.6",
"d3-selection": "^1.4.0",
"d3-zoom": "^1.7.3",
Expand Down
3 changes: 2 additions & 1 deletion src/GraphContext/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ export const Provider = (props) => {
}
});


const graphContext = {
state,
dispatch,
onConnect,
dispatch
};

return (
Expand Down
46 changes: 24 additions & 22 deletions src/NodeRenderer/NodeTypes/wrapNode.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useEffect, useRef, useContext, useState, memo } from 'react';
import React, { useEffect, useRef, useState, memo } from 'react';
import ReactDraggable from 'react-draggable';
import cx from 'classnames';

import { GraphContext } from '../../GraphContext';
import { updateNodeData, updateNodePos, setSelectedElements } from '../../state/actions';
import { isNode } from '../../graph-utils';
import { Provider } from '../NodeIdContext';
Expand Down Expand Up @@ -60,36 +59,38 @@ const onDrag = (evt, { dispatch, id, offset, transform }) => {
}));
};

const onNodeClick = (evt, { onClick, dispatch, data, id, type, position }) => {
const onNodeClick = (evt, { onClick, dispatch, id, type, position, data }) => {
if (isInput(evt)) {
return false;
}

dispatch(setSelectedElements({ data, id }));
onClick({ id, type, data, position });
const node = { id, type, position, data }

dispatch(setSelectedElements(node));
onClick(node);
};

const onStop = ({ onNodeDragStop, id, type, data, position }) => {
const onStop = ({ onNodeDragStop, id, type, position, data }) => {
onNodeDragStop({
id,
type,
data,
position
id, type, position, data
});
};

export default NodeComponent => memo((props) => {
const nodeElement = useRef(null);
const { state, dispatch } = useContext(GraphContext);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const {
data, onClick, type, id, __rg, onNodeDragStop
id, type, data, transform, xPos, yPos, selectedElements,
dispatch, getNodeById, onClick, onNodeDragStop
} = props;
const { position } = __rg;
const [ x, y, k ] = state.transform;
const selected = state.selectedElements.filter(isNode).map(e => e.id).includes(id);

console.log('render node', id);

const position = { x: xPos, y: yPos };
const [ x, y, k ] = transform;
const selected = selectedElements.filter(isNode).map(e => e.id).includes(id);
const nodeClasses = cx('react-graph__node', { selected });
const nodeStyle = { zIndex: selected ? 10 : 3, transform: `translate(${position.x}px,${position.y}px)` };
const nodeStyle = { zIndex: selected ? 10 : 3, transform: `translate(${xPos}px,${yPos}px)` };

useEffect(() => {
const bounds = nodeElement.current.getBoundingClientRect();
Expand All @@ -105,21 +106,22 @@ export default NodeComponent => memo((props) => {

return (
<ReactDraggable.DraggableCore
onStart={evt => onStart(evt, { setOffset, transform: state.transform, position })}
onDrag={evt => onDrag(evt, { dispatch, id, offset, transform: state.transform })}
onStop={() => onStop({ onNodeDragStop, id, type, data, position })}
scale={state.transform[2]}
onStart={evt => onStart(evt, { setOffset, transform, position })}
onDrag={evt => onDrag(evt, { dispatch, id, offset, transform })}
onStop={() => onStop({ onNodeDragStop, id, type, position, data })}
scale={transform[2]}
>
<div
className={nodeClasses}
ref={nodeElement}
style={nodeStyle}
onClick={evt => onNodeClick(evt, { onClick, dispatch, data, id, type, position })}
onClick={evt => onNodeClick(evt, { getNodeById, onClick, dispatch, id, type, position, data })}
>
<Provider value={id}>
<NodeComponent {...props} selected={selected} />
</Provider>
</div>
</ReactDraggable.DraggableCore>
);
});
}
);
79 changes: 43 additions & 36 deletions src/NodeRenderer/index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
import React, { PureComponent } from 'react';
import React, { memo, useContext } from 'react';

import { Consumer } from '../GraphContext';
import { GraphContext } from '../GraphContext';

class NodeRenderer extends PureComponent {
function renderNode(d, props, graphContext) {
const nodeType = d.type || 'default';

renderNode(d) {
const nodeType = d.type || 'default';
if (!this.props.nodeTypes[nodeType]) {
console.warn(`No node type found for type "${nodeType}". Using fallback type "default".`);
}

const NodeComponent = this.props.nodeTypes[nodeType] || this.props.nodeTypes.default;

return (
<NodeComponent
key={d.id}
onClick={this.props.onElementClick}
onNodeDragStop={this.props.onNodeDragStop}
onConnect={this.props.onConnect}
{...d}
/>
);
if (!props.nodeTypes[nodeType]) {
console.warn(`No node type found for type "${nodeType}". Using fallback type "default".`);
}

render() {
return (
<Consumer>
{({ state }) => (
<div
className="react-graph__nodes"
style={{
transform: `translate(${state.transform[0]}px,${state.transform[1]}px) scale(${state.transform[2]})`
}}
>
{state.nodes.map(d => this.renderNode(d))}
</div>
)}
</Consumer>
);
}
const NodeComponent = props.nodeTypes[nodeType] || props.nodeTypes.default;

return (
<NodeComponent
key={d.id}
id={d.id}
type={d.type}
data={d.data}
xPos={d.__rg.position.x}
yPos={d.__rg.position.y}
onClick={props.onElementClick}
onNodeDragStop={props.onNodeDragStop}
dispatch={graphContext.dispatch}
transform={graphContext.state.transform}
getNodeById={graphContext.getNodeById}
selectedElements={graphContext.state.selectedElements}
/>
);
}

const NodeRenderer = memo((props) => {
const graphContext = useContext(GraphContext);
const { transform, nodes } = graphContext.state;

return (
<div
className="react-graph__nodes"
style={{
transform: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`
}}
>
{nodes.map(d => renderNode(d, props, graphContext))}
</div>
);
});

NodeRenderer.displayName = 'NodeRenderer';
NodeRenderer.whyDidYouRender = false;

export default NodeRenderer;
5 changes: 5 additions & 0 deletions src/ReactGraph/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import React, { PureComponent } from 'react';

if (process.env.NODE_ENV !== 'production') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React);
}

import { parseElements, separateElements } from '../graph-utils';
import GraphView from '../GraphView';
import GlobalKeyHandler from '../GlobalKeyHandler';
Expand Down

0 comments on commit ec7231e

Please sign in to comment.