-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Library breaks when trying to create an Edge from a Handle that is generated programmatically #805
Comments
I'm using dynamic handles with no issues, connection lines find the handles by their IDs and types. if you're getting const sourceHandle = handleId
? sourceNode.__rf.handleBounds[connectionHandleType].find((d: HandleElement) => d.id === handleId)
: sourceNode.__rf.handleBounds[connectionHandleType][0]; handleBounds is not being updated, this is set when const handles = nodeElement.querySelectorAll(selector);
if (!handles || !handles.length) {
return null;
} maybe hack in some extra renders on your node to see if that magically fixes it, then we can figure out why. |
Hi @RickeyWard , thanks a lot for the support! |
Thanks @RickeyWard! I also think that the problem here is that the nodes are not re-initialized. Respectively the nodes are getting initialized without handles or with a different number and then we don't update them. It would be helpful to have a way to update the node dimensions programmatically. |
A way to update the node dimensions programmatically sounds like a great idea, what I'm having trouble identifying is why I can programmatically create handles with no issues and @StefanoSega can't I have a node that starts with no outbound edges, and has a button that adds a new one. they are stored in the data attribute and are mapped virtually identically to the OPs map. I allow editing in a side pane as well, and when the options are updated the handles also work as expected. |
I have a very similar problem to this. For my use case, users have the ability to edit the identifiers associated with handles, which causes the calculated pin positions to fall out of sync until the node is resized or fully recalculated because it's fallen out of view. I'm not sure what the best solution is, my current thought is to add a MutationObserver to the root div of the node which invokes updateNodeDimensions whenever the contents mutate, but it's not obvious to me if there's a simpler way to cause the existing effects in wrapNode.tsx to fire instead. |
I ran into this issue today, after some experimentation I found what was triggering this, and the potential answer to
I have a feature for adding custom labels onto nodes as part of the UI. What I found was that if adding/removing dynamic handles alters the width of the element (i.e. the calculated width based on handle count grows/shrinks past the width of the custom label), then dynamic ports work fine, however if adding the dynamic handle does not alter the width of the element, then it crashes out. This can be observed in image posted as part of #811 - in the example given, adding the handle does not affect the size of the element which leads to the issue at hand. So it may be that @RickeyWard's implementation causes the component's width to change whereas @StefanoSega may have fixed size components? |
My use case doesn't cause the width to change but it does cause the height to change. Maybe that's it this probably needs some attention to be more deterministic. |
For clarification: We are updating the node internals whenever a node mounts or changes the |
I haven't had time to push that up, but I have it working in my app. I'll post an updated PR that uses the hook instead in the next day or two. |
In v9.1.0 we added a Usage: import { useUpdateNodeInternals } from 'react-flow-renderer';
// ....
const updateNodeInternals = useUpdateNodeInternals();
// somewhere in your app
updateNodeInternals('node-id'); Does this solve your issue? |
It already worked in my particular case because of resizing, but I added this in also and it still behaves as expected for me. |
I will close this issue since the |
When should I call the In my implementation, I have a textfield that asks for the no. of handles in a Custom Node component. So, here in the below code, I call the const ChatTriggerContents = ({ widgetData, handleTextChange }) => {
const updateNodeInternals = useUpdateNodeInternals()
useEffect(() => {
Array.from({ length: widgetData.data.transitionCount }).forEach((_trans, _transIndex) => {
updateNodeInternals(`handle_${_transIndex}`)
})
}, [widgetData.data.transitionCount, updateNodeInternals])
return (
<>
<Typography className="font-bold p-2 text-center">{widgetData?.data?.action_name}</Typography>
{Array.from({ length: widgetData?.data?.transitionCount ?? 0 }).map((_trans, _transIndex) => {
return (
<Handle
key={`handle_${_transIndex}`}
id={`handle_${_transIndex}`}
type="source"
style={{ left: `${getPos(_transIndex, parseInt(widgetData?.data?.transitionCount, 10))}%` }}
position="bottom"
/>
)
})}
</>
)
} |
updateNodeInternals takes the ID of the node, you are passing the ID of the handle, |
Ohh My Bad. Thanks. It works now. |
Using
|
From the docs
Have you included the provider in your component tree as requested by the error? |
Hi Jaspooky, I missed that provider part in doc, it is working now when implemented in children of provider. |
my component with react flow is included in the react flow provider. useUpdateNodeInternals is connected and works without errors. only it does not update the CustomNode. I wanted to ask if I'm doing the right thing - I make changes to the object of the desired CustomNode, update the elements using setElements and then call useUpdateNodeInternals ("id_my_customNode"), for example, useUpdateNodeInternals("2"). at the same time, there are changes in the CustomNode object, but the content of the CustomNode in the DOM tree does not change |
Works like a charm! Could you also add a simple function that does that? My |
The api for the library is hook-heavy, slippery slope to start adding reference functions for all the actions and since no non-hook state updates exist in the internal api it would end up being burying a work around in the library instead of the client code. I'd recommend using functional components when working with react-flow as that's how the library is written but the easiest escape hatch would be a forwardref and an imperative handle. (note that you could always just call the redux dispatch event that performs the update but since that's relying on the state library not changing I strongly recommend against it and always targeting the outward facing api) Example for creating an imperative api exposing component. (completely untested written in this comment, but I'm pretty sure it's all there.)
Then you can just render this Component in your Node and use the ref to access the object. In fact you could grab all the hook functions you wanted to and add them to the ref. The ref will expose the object returned by the useImperativeHandle callback, so go to town and have a good time.
|
Hi, I've ran into the dynamic handles issue - i'm adding a new source handle and edge from a UI interaction. I've implemented the
(the This fixes the edge not being drawn correctly, however I still get a warning beforehand for Thanks! |
@CheesyFeet The useEffect on number of outputs is exactly how I use it, works fine. What's more likely is that your handle IDs are not consistent or your edges are being created with the the wrong data, that warning happens when there exists an edge with source, sourcehandle, target, targehandle sets that can't be found in the graph. If you are seeing the handles then they are there, but the IDs possibly don't match. The code snippet above is fine. updateNodeInternals should happen after the new handle is added. But its important that the node never get rendered without that handle afterwards (unless you've removed all edges that reference it) and also that the handle ID doesn't change. |
Hi, everyone! I had the same problem as @StefanoSega . |
Hi guys!
First of all, thanks for the amazing library that React Flow is.
I've a Custom Node where I need to programmatically generate the Source Handles based on a list stored in
data
; the list is namedgroups
and contains strings like '1', '2', ...id
is the Node Id.The Node is generated correctly showing an handle for each group, but when I try to drag a Edge out of the Handle I get this error:
The text was updated successfully, but these errors were encountered: