Skip to content
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

useUpdateNodeInternals doesn't update edges after moving handles #2008

Closed
AndrewRayCode opened this issue Mar 23, 2022 · 9 comments
Closed
Assignees

Comments

@AndrewRayCode
Copy link

AndrewRayCode commented Mar 23, 2022

Describe the Bug

I move my component handles around dynamically. The edges to those handles don't move, and any additional attempt to connect edges to the moved handles fails, the edges get connected to the wrong place. I'm using useUpdateNodeInternals but it doesn't work as I would expect.

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

I have a custom handle component like this:

const CustomHandle = ({ nodeId, id, handleIndex, ...props }: any) => {
  const updateNodeInternals = useUpdateNodeInternals();
  useEffect(() => {
      updateNodeInternals(nodeId);
  }, [nodeId, updateNodeInternals, handleIndex, id]);

  return <Handle id={id} {...props} />;
};

this is to try to force the edges to update correctly after I move handles around. I render it like this:

{data.inputs.map((input, index) => (
          <React.Fragment key={input.name}>
            <div
              className="react-flow_handle_label"
              style={{
                top: `${handleTop - textHeight + index * 20}px`,
                left: 15,
              }}
            >
              {input.name}
            </div>
            <CustomHandle
              handleIndex={index}
              nodeId={id}
              id={input.name}
              className={cx({ validTarget: input.validTarget })}
              type="target"
              position={Position.Left}
              style={{ top: `${handleTop + index * 20}px` }}
            />
          </React.Fragment>
        ))}

Expected behavior

In this case the effect fires, but the edge does not get moved to the right place. The edge stays stuck to the stale handle even after the handles update and the effect runs.

Sadly, this works:

const CustomHandle = ({ nodeId, id, handleIndex, ...props }: any) => {
  const updateNodeInternals = useUpdateNodeInternals();
  useEffect(() => {
    setTimeout(() => {
      updateNodeInternals(nodeId);
    }, 0);
  }, [nodeId, updateNodeInternals, handleIndex, id]);

  return <Handle id={id} {...props} />;
};

the settimeout indicates to me there's some state/updating issue going on.

Screenshots or Videos

No response

Platform

Mac Chrome 10.0.3

Additional context

Related to #916

Discord convo starts here https://discord.com/channels/771389069270712320/859774873500778517/956236629603926046

As a consumer of react-flow, useUpdateNodeInternals is the first part of the API I personally find "ugly" - it's an imperative manual user step and it's unclear when it should be fired, and this issue indicates to me it's exposing some state update ordering that the end consumer shouldn't have to worry about. Also this is not something obvious to google for, I didn't discover it in the docs myself, someone in discord pointed me to this API. Ideally updating handles would "just work" out of the box.

@AndrewRayCode
Copy link
Author

Actually after my setTimeout update, it put the edge right in the middle of the node, so I think i'm still missing something

Screen Shot 2022-03-23 at 11 56 12 AM

@Sec-ant
Copy link
Contributor

Sec-ant commented Mar 24, 2022

do you have animations when moving the handles?

@AndrewRayCode
Copy link
Author

I don't animate the position of anything in my graph. I have some css animations which animate the opacity of drop shadows and border colors when dragging connection lines to indicate which targets are droppable, but I don't think that's what you mean

@onlaps
Copy link

onlaps commented Mar 24, 2022

having same problem with repositioning edge when node's size is chaning

@andreas-schultz
Copy link

andreas-schultz commented Apr 7, 2022

This might be a regression. I had the same problem (putting all edges into the middle) with a 9.x version, changing the version to 9.6.1 made updateNodeInternals work again for me. Just checked, version 9.7.4 also seems to work fine.

@CamboimGabriel
Copy link

did you solved?

@moklick
Copy link
Member

moklick commented Jul 18, 2022

Did you try to add props.style to the useEffect ? Could someone create a codesandbox or repo for this specific case?

@moklick
Copy link
Member

moklick commented Aug 16, 2022

Could you try to use v10.3.15 ? It should work better now.

@RAFA3L
Copy link

RAFA3L commented Dec 9, 2022

I have a similar problem trying to delete orphans edges dynamically, my handles are dependent of values in fields, so I need to delete the edges when the fields are updated and the handles removed.

This is weird, inside a custom node I try this:

useEffect(() => {
  console.log(nodeInternals); // updated
  console.log(nodeInternals.get(props.id)); // old
}, [nodeInternals, props.id]);

The first log print the updated state of the handleBounds (inspecting the node in the tree map), but the second print the node with the old state.

Using the setTimeout suggested by @AndrewRayCode works, so I can get the updated handleBounds and remove the edges:

  useEffect(() => {
    setTimeout(() => {
      const node = nodeInternals.get(props.id);
      const propSymbols = Object.getOwnPropertySymbols(node);
      const handleBounds = node[propSymbols[0]].handleBounds;
      const orphans = edges.filter(
        (e) =>
          e.source === node.id &&
          !handleBounds.source.find((h) => h.id === e.sourceHandle)
      );
      reactFlowInstance.deleteElements({ edges: orphans });
    }, 0);
  }, [nodeInternals, props.id, edges, reactFlowInstance]);

And in my field changes handle something like this:

  const handleChanges = (e) => {
    updateNodeFields(node.id, e.formData, e.errors);
    updateNodeInternals(node.id);
  };

Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants