chrisjpatty / flume

Extract logic from your apps with a user-friendly node editor powered by React.
https://flume.dev
MIT License
1.44k stars 148 forks source link

NodeEditor: (re)setting the nodes prop does not update the editor contents #38

Open andraz-at opened 4 years ago

andraz-at commented 4 years ago

A common React expectation is that changing the child nodes prop triggers a re-render of the component.

I am trying to externally manipulate nodes prop to control the NodeEditor programmatically using Mobx State Tree with observers. It is intended to work like a "remote control" for the NodeEditor's UI, setting/updating some internal state, then (when all nodes are wired up) letting user to play around and experiment on its own.

Example on CS link below prints a comment each time re-render is performed, NodeEditor does not update the contents on this re-render (if change is coming from the outside). The current state is rendered as JSON in the middle of the screen for easier monitoring. Adding nodes with right click works ok.

I've added a button to toggle the parent NodeEditor component rendering, which can be used to manually perform the update by first removing NodeEditor from the dom, then rendering it back. This works, but I still hope there is a less brutal way to achieve a refresh. 🙂

https://codesandbox.io/s/mst-flume-control-4y1xl?file=/src/flume.js

p.s.: Connections between nodes disappear after toggling the NodeEditor off and then back on. Trying to do changes to nodes after that cause errors to appear.

chrisjpatty commented 4 years ago

Ah, yeah you've discovered a constraint here with how the editor is currently designed. Right now the editor goes through a reconciliation phase if the editor is loaded with existing nodes. That reconciliation phases goes through the supplied nodes and coerces them to match the schema of the node types and input types. It could potentially become a performance hit if the editor needed to re-run the reconciliation every time the provided nodes change from the parent component. For that reason and a few others, the node editor technically always runs in an "uncontrolled" way, and internally manages its own state. But you're right that this can lead to some unexpected behavior when you try to manually provide a new set of nodes.

Would it work for you if there was an imperative function exposed on the editor that would force the reconciliation to run and reset the the nodes? Something like:

const nodeEditor = React.useRef();

const setNewNodes = () => {
  nodeEditor.setNodes({...newSetOfNodes})
}

return (
  <div>
    <button onClick={setNewNodes}>Set New Nodes</button>
    <NodeEditor ref={nodeEditor} />
  </div>
)

There may be a better way to handle this in the future to with some more advanced reconciliation of previous and current nodes, but would this work for your use case in the meantime?

andraz-at commented 4 years ago

Yes, if I can get NodeEditor ref function to trigger an update manually, then I can control the updates that way.

p.s.: The connections bug was on the store side, NodeEditor now renders all connections ok, example on link updated.

netgfx commented 4 years ago

Is this a feature are are waiting on? or is there something we can use to dynamically add nodes?

NicWickman commented 3 years ago

Signal boosting. This is a must.

7coil commented 1 week ago

I've cheated by forcing a re-render of the component. Probably a bad idea, but the only way I can get it to work...

You can do this by creating a new state like const [renderKey, setRenderKey] = useState<number>(0);, then changing the key on <NodeEditor /> every time you run setNodes