We’re using gojs within a react app and we have a few functions that return templates which roughly look like this:
function getContextMenuTemplate(onContextMenuButtonClick) {
return go.GraphObject.make('ContextMenuButton', {
click: (e: go.InputEvent, obj: go.GraphObject) {
onContextMenuButtonClick(e.part);
}
})
}
function getNodeTemplate(onContextMenuButtonClick) {
return new go.Node(go.Panel.Spot, { // ... })
.add(
go.GraphObject.make('Button', {
contextMenu: getContextMenuTemplate(onContextMenuButtonClick),
}
);
}
Upon initializing the canvas we pass a function into the template for the context menu callbacks. This function depends on a react state. Again, roughly:
function Blah() {
let [x, setX] = useState(false);
diagram.nodeTemplateMap = getNodeTemplate((part) => {
if (x) {
console.log("part was clicked");
}
});
}
Since the function passed into the getNodeTemplate
closes over the x
value it’ll only see the initial value of x
and when x
is updated to true
, this function still sees it as false
. This is classic closure problem and has nothing to do with gojs. And then reason for it is because we only set the diagram template once and at that moment the captured value of x
is false.
Now one way to fix this is to use useRef
and instead of if (x)
use if (xRef.current)
and update the ref within an effect. But I don’t like this at all.
Another way to do this, which we do for most of other event handlers, is to attach an events handler to the diagram, like:
useEffect(() => {
diagram.addDiagramListener('some_event', callback);
return () => {
diagram.removeDiagramListener('some_event', callback);
}
}, [x])
^ This way I can update the remove the listener and add a new one once the closure variables are updated.
The problem is, I haven’t been able to find an event that works with ContextMenu
. The closest one I found is ObjectSingleClicked
but it’s tricky to get the data off of e.subject
cause the subject
is sometimes the TextBox
which renders the button text and sometimes the Shape behind the text.
Does this make sense? In short, I wanna attach an events listener to the diagram that fires every time a Button within ContextMenu
is clicked and tells me which button it was and the data attached to that node.
I can create a small repro on stackblitz if it helps but thought throw this out here first just in case I’m doing it totally wrong.