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

React-dnd hijacks out of context "draggable" elements #3304

Open
rogerfar opened this issue Sep 16, 2021 · 9 comments
Open

React-dnd hijacks out of context "draggable" elements #3304

rogerfar opened this issue Sep 16, 2021 · 9 comments

Comments

@rogerfar
Copy link

rogerfar commented Sep 16, 2021

When calling useDrop it will effectively remove all dragging capabilities from your app, even if they are outside the DndProvider container.

See:
https://codesandbox.io/s/festive-sky-muxxt?file=/src/index.js

Try dragging the red square, it's marked as draggable which means it should show the HTML5 dragging overlay.

The issue is that I'm allowing components to be dragged in from outside the DndProvider because it's using react-grid-layout, but react-dnd breaks it.

@tylucaskelley
Copy link

Also seeing this. react-dnd version 14.0.4. We have a table component w/ draggable rows that uses react-dnd, but not every other component in the system has been updated to use it as well, and it feels like if its usage is isolated to one place it shouldn't be taking over all drag events

@MinJieLiu
Copy link

+1
Is there a solution now?

@RafaelGB
Copy link

RafaelGB commented Aug 8, 2022

Reading the documentation I found one way to approach this use case.
Works for me!

// ...
const DnDRef = React.useRef(null);
// ...
<div
      key={`${headerGroup.id}-${headerGroupIndex}`}
      className={`${c("tr header-group")}`}
      ref={DnDRef} <-- Create your context
>
  <DndProvider
        key={`${headerGroup.id}-${headerGroupIndex}-dnd-provider`}
        backend={HTML5Backend}
        context={DnDRef} <-- Use the context you create
    >
    {// ...}
  </DndProvider>
</div>

@Ytime
Copy link

Ytime commented Sep 22, 2022

It seems that there is something wrong with RafaelGB's solution. DnD don't work correctly.
https://codesandbox.io/s/infallible-bardeen-8fh98f?file=/src/index.js

@RafaelGB
Copy link

My use case was to fix an incompatibility with an architecture element used by my component (a plugin). I was able to fix it but finally dispensing with react-dnd.

The problem came in the usedrop declaration since it affects all those components with the "onDrop" event loaded disabling them.

Depends of your case just use native dnd

@Ytime
Copy link

Ytime commented Sep 23, 2022

Thank you for your reply which solved my doubt!

Some of my imported components use native dnd. These components and react-dnd are not compatible at the same time.😭

@Ytime
Copy link

Ytime commented Sep 23, 2022

Thank you for your reply which solved my doubt!

Some of my imported components use native dnd. These components and react-dnd are not compatible at the same time.😭

I found the reason why dnd don't work.(referring to #3344)

function DndProviderWrapper({ className, children }) {
  const context = useRef(null);
  const dndArea = context.current;
  const html5Options = useMemo(() => ({ rootElement: dndArea }), [dndArea]);
  return (
    <div className={className} ref={context}>
      {// it is important that DndProvider don't render if dndArea is null }
      {dndArea && (
        <DndProvider backend={HTML5Backend} options={html5Options}>
          {children}
        </DndProvider>
      )}
    </div>
  );
}

// ...
<div>
  <DndProviderWrapper>
    {// ... your component used react-dnd}
  </DndProviderWrapper>
 {// ... your component used native dnd}
</div>

@lionnel-afan
Copy link

Thank you all for addressing this !
I had the same issue this week and it wasn't clear what exactly was causing the problem until I figured out it was the DndProvider + useDrop combination.
Ytime's solution works great for my use case (thanks for the solution!), although I had to tweak it a little :

const DndProviderWrapper: React.FC<any> = ({ className, children }) => {
    const context = useRef(null);
    //Make the dndAre a part of the component state otherwise, some times, the content doesn't renders
    const [dndArea, setDnDArea] = useState(context.current);
    //additionally, add a useEffect to track the context reference => might be overkill performance wise but works for my use case
    useEffect(() => {
        setDnDArea(context?.current);
    }, [context])
    const html5Options = useMemo(() => ({ rootElement: dndArea }), [dndArea]);
    return (
        <div className={className} ref={context}>
            {/* it is important that DndProvider don't render if dndArea is null */}
            {dndArea && (
                <DndProvider backend={HTML5Backend} options={html5Options}>
                    {children}
                </DndProvider>
            )}
        </div>
    );
}

@Atrus619
Copy link

I had the exact same problem and the above fixed my issue. Should consider merging this into the next release.

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