I am trying to use cytoscape.js in react.js but while passing the reference in cytoscape function I am facing some errors.
var cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: cytoscape.stylesheet()
.selector('node')
.style({
'content': 'data(id)'
})
.selector('edge')
.style({
'curve-style': 'bezier',
'target-arrow-shape': 'triangle',
'width': 4,
'line-color': '#ddd',
'target-arrow-color': '#ddd'
})
.selector('.highlighted')
.style({
'background-color': '#61bffc',
'line-color': '#61bffc',
'target-arrow-color': '#61bffc',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}),
elements: {
nodes: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } }
],
edges: [
{ data: { id: 'ae', weight: 1, source: 'a', target: 'e' } },
{ data: { id: 'ab', weight: 3, source: 'a', target: 'b' } },
{ data: { id: 'be', weight: 4, source: 'b', target: 'e' } },
{ data: { id: 'bc', weight: 5, source: 'b', target: 'c' } },
{ data: { id: 'ce', weight: 6, source: 'c', target: 'e' } },
{ data: { id: 'cd', weight: 2, source: 'c', target: 'd' } },
{ data: { id: 'de', weight: 7, source: 'd', target: 'e' } }
]
},
layout: {
name: 'breadthfirst',
directed: true,
roots: '#a',
padding: 10
}
});
It's showing error while compiling
TypeError: Cannot read properties of null (reading 'className')
Renderer.push../node_modules/cytoscape/dist/cytoscape.cjs.js.BRp$f.init
26869 | var className = '__________cytoscape_container';
26870 | var stylesheetAlreadyExists = document.getElementById(stylesheetId) != null;
26871 |
> 26872 | if (ctr.className.indexOf(className) < 0) {
| ^ 26873 | ctr.className = (ctr.className || '') + ' ' + className;
26874 | }
Is there is any way to solve this problem?
I also tried using Refs to solve this problem instead of using document.getElementById() but getting the same error.
There was such a mistake. I used React hooks: useEffect and useRef. Everything works if you initiate cytoscape after rendering the page.
import React, { useEffect, useRef } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import cytoscape from "cytoscape";
const useStyles = makeStyles(theme => ({
graph: {
height: 787,
width: '100%',
maxHeight: 787,
}
}));
const Graph = props => {
const classes = useStyles();
const graph = useRef(null);
const cy = useRef(null);
useEffect(() => {
if (graph.current) {
cy.current = cytoscape({
container: graph.current,
elements: {
nodes: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } }
],
edges: [
{ data: { id: 'ae', weight: 1, source: 'a', target: 'e' } },
{ data: { id: 'ab', weight: 3, source: 'a', target: 'b' } },
{ data: { id: 'be', weight: 4, source: 'b', target: 'e' } },
{ data: { id: 'bc', weight: 5, source: 'b', target: 'c' } },
{ data: { id: 'ce', weight: 6, source: 'c', target: 'e' } },
{ data: { id: 'cd', weight: 2, source: 'c', target: 'd' } },
{ data: { id: 'de', weight: 7, source: 'd', target: 'e' } }
]
},
ready: function () {
window.cy = this;
}
});
}
}, []);
return (
<div
className={classes.graph}
ref={graph}
>
</div>
);
};
export default Graph;