Reputation: 12729
I am trying to update my view after two seconds. But it's not calling update view, why?
Here is my code https://codesandbox.io/s/practical-driscoll-5cvmm
Initial view is displayed but after two seconds it is not updating the DOM.
var fsm = new StateMachine({
init: "open",
transitions: [
{ name: "clodsdse", from: "open", to: "closed" },
{ name: "open", from: "closed", to: "open" },
{ name: "openss", from: "closed", to: "open" },
{ name: "ss", from: "a", to: "b" }
]
});
useEffect(() => {
d3.select("#graph")
.graphviz()
.renderDot(visualize(fsm));
setTimeout(() => {
console.log("---");
update();
}, 2000);
}, []);
Upvotes: 1
Views: 535
Reputation: 3644
First of all, I think you should save your Graph data into your state, then in your useEffect
hook, you can call setFsm
to rerender your Graph.
You can also partially update your Graph data but in the following example I will just replace with your new Graph data instead.
You should also call clearTimeout
in your useEffect
return function to prevent memory leak in your app ( Just in case the component is unmounted before setFsm
is called )
One thing I've realized on the previous answer is that, everytime fsm
is updated, it will call setTimeout
again, which result in fsm
to update, which result in another setTimeout
, essentially its like an endless loop. I've updated my answer so that the setTimeout
is only called onMount
, and another useEffect
is just for rendering / updating the Graph. I think codes like this makes more sense.
You can use this code as your reference.
function App() {
const [fsm, setFsm] = useState({
init: "open",
transitions: [
{ name: "clodsdse", from: "open", to: "closed" },
{ name: "open", from: "closed", to: "open" },
{ name: "openss", from: "closed", to: "open" },
{ name: "ss", from: "a", to: "b" }
]
});
const renderGraph = () => {
d3.select("#graph").graphviz().renderDot(visualize(new StateMachine(fsm)));
};
// for graph rendering after each update
useEffect(renderGraph, [fsm]);
// only setTimeout onMount and clearTimeout willUnmount
useEffect(() => {
const timer = setTimeout(() => {
setFsm({
init: "open",
transitions: [
{ name: "clodsdse", from: "open", to: "closed" },
{ name: "open", from: "closed", to: "open" },
{ name: "openss", from: "closed", to: "open" },
{ name: "ss", from: "a", to: "b" },
{ name: "sasdss", from: "a", to: "bb" }
]
});
}, 2000);
return () => {
clearTimeout(timer);
};
}, []);
return (
<div className="App">
<div id="graph" />
</div>
);
}
Upvotes: 4
Reputation: 395
I replace window.d3
by only d3
and it works.
const update = i => {
var fsm = new StateMachine({
init: "open",
transitions: [
{ name: "clodsde" + i, from: "open", to: "closed" },
{ name: "open", from: "closed", to: "open" },
{ name: "openss", from: "closed", to: "open" },
{ name: "ss", from: "a", to: "b" },
{ name: "sasdss", from: "a", to: "bb" }
]
});
d3.select("#graph")
.graphviz()
.renderDot(visualize(fsm));
};
useEffect(() => {
d3.select("#graph")
.graphviz()
.renderDot(visualize(fsm));
var i = 0;
setInterval(() => {
console.log("---");
update(i);
i++;
}, 2000);
Also I replace setTimeout by setInterval to update it every 2 sec.
Upvotes: 2
Reputation: 17654
Don't use window.d3
, use d3
:
const update = () => {
var fsm = new StateMachine({
init: "open",
transitions: [
{ name: "clodsdse", from: "open", to: "closed" },
{ name: "open", from: "closed", to: "open" },
{ name: "openss", from: "closed", to: "open" },
{ name: "ss", from: "a", to: "b" },
{ name: "sasdss", from: "a", to: "bb" }
]
});
d3 // <-- not window.d3
.select("#graph")
.graphviz()
.renderDot(visualize(fsm));
};
Upvotes: 2