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

Multiple DndProviders inside a pure component can lead to Cannot have two HTML5 backends at the same time #3257

Open
dcsaszar opened this issue Jul 14, 2021 · 19 comments

Comments

@dcsaszar
Copy link

Describe the bug

Using two <DndProvider backend={HTML5Backend}> inside a React.PureComponent (which updates only if props change), can under certain conditions lead to an error like:

Error: Cannot have two HTML5 backends at the same time.
	    at HTML5BackendImpl.setup node_modules/react-dnd-html5-backend/dist/esm/HTML5BackendImpl.js:423
	    at DragDropManagerImpl.handleRefCountChange node_modules/dnd-core/dist/esm/classes/DragDropManagerImpl.js:21
	    at Object.dispatch node_modules/redux/es/redux.js:297
	    at HandlerRegistryImpl.addSource node_modules/dnd-core/dist/esm/classes/HandlerRegistryImpl.js:92
	    at registerSource node_modules/react-dnd/dist/esm/internals/registration.js:10
	    at registerDragSource node_modules/react-dnd/dist/esm/hooks/useDrag/useRegisteredDragSource.js:24
	    at commitHookEffectListMount node_modules/react-dom/cjs/react-dom.development.js:20573
	    at commitLifeCycles node_modules/react-dom/cjs/react-dom.development.js:20634
	    at commitLayoutEffects node_modules/react-dom/cjs/react-dom.development.js:23426
	    at HTMLUnknownElement.callCallback node_modules/react-dom/cjs/react-dom.development.js:3945
	    at Object.invokeGuardedCallbackDev node_modules/react-dom/cjs/react-dom.development.js:3994
	    at invokeGuardedCallback node_modules/react-dom/cjs/react-dom.development.js:4056
	    at commitRootImpl node_modules/react-dom/cjs/react-dom.development.js:23151
	    at unstable_runWithPriority node_modules/scheduler/cjs/scheduler.development.js:468
	    at runWithPriority$1 node_modules/react-dom/cjs/react-dom.development.js:11276
	    at commitRoot node_modules/react-dom/cjs/react-dom.development.js:22990

Reproduction

This is the smallest reproducing example I was able to come up with:
https://codepen.io/dcsaszar/pen/ZEKLVVJ

It describes basically what happens in one of our apps: Inside a PureComponent-like component (we have our own abstraction, but with a similar implementation of shouldComponentUpdate), we have a single read-only (this is a prop, in the example: foo) DnD component, which later is dynamically replaced by a single read-write DnD component, and then joined by a 2nd DnD component.

Steps to reproduce the behavior:

  1. Go to https://codepen.io/dcsaszar/pen/ZEKLVVJ
  2. See the error in the browser console

Expected behavior

  • No error.
  • The components should render successfully.

Desktop

  • Browser: Chrome
  • Version:
    • react 17.0.2
    • react-dnd: 14.0.2
    • react-dnd-html5-backend: 14.0.0

Related
#1558
#3119
#3178

Since I wasn't sure which/if any of the above qualifies for duplicate, I created a fresh issue.

@ismailmmd
Copy link

+1 Getting the same error

I am using version 7.7.0 for both react-dnd and react-dnd-html5-backend

Cannot have two HTML5 backends at the same time.

      206 |
    > 207 |             const wrapper = mount(
          |                             ^
      208 |                     <Provider store={store}>
      209 |                             <DragDropContextProvider backend={HTML5Backend}>
      210 |                                     <MyComponent />

      at HTML5Backend.Object.<anonymous>.HTML5Backend.setup (node_modules/react-dnd-html5-backend/lib/cjs/HTML5Backend.js:318:19)
      at DragDropManagerImpl.handleRefCountChange (node_modules/dnd-core/lib/cjs/DragDropManagerImpl.js:30:31)

@piechoo
Copy link

piechoo commented Aug 30, 2022

Got the same issue with
"react-dnd": "16.0.0", "react-dnd-html5-backend": "16.0.0",

@ymh1028
Copy link

ymh1028 commented Sep 7, 2022

add props context={window}, it's solved my problem.

@emileWhispa
Copy link

add props context={window}, it's solved my problem.

Thanks you saved my ass

@ZijieZh
Copy link

ZijieZh commented Dec 12, 2022

thx

add props context={window}, it's solved my problem too.
with version:
"react-dnd": "^9.4.0",
"react-dnd-html5-backend": "^9.4.1",

@aovchinn
Copy link

should this context prop be documented somehow ?

@aovchinn
Copy link

should this be true by default ?
const isGlobalInstance = !props.context

const isGlobalInstance = !props.context

@echoyl
Copy link

echoyl commented Feb 15, 2023

add props context={window}, it's solved my problem.

thx,it works

@clfuture
Copy link

Got the same issue with "react-dnd": "16.0.0", "react-dnd-html5-backend": "16.0.0",

Have you solved this problem yet? My version is "react-dnd": "^14.0.4", "react-dnd-html5-backend": "^14.0.2",

@coder-zhuzm
Copy link

add props context={window}, it's solved my problem.

有用的!!!

@ekeijl
Copy link

ekeijl commented Nov 14, 2023

For people still struggling with this: the issue mostly seems to occur when you wrap your DnD enabled component directly with a DnDProvider (instead of using the Provider at the top level of your app) and then navigating between routes/pages in your app.

I see two workarounds:

  • Wrap your top level <App> component with the <DnDProvider> and remove any other DnDProvider components. This ensures there can only ever be a single instance of the HTML5 backend.
  • Add the context={window} prop on the provider <DndProvider backend={HTML5Backend} context={window}>.

@pvrameshkf
Copy link

Thanks a lot @ekeijl . Below solution worked for me.

Add the context={window} prop on the provider <DndProvider backend={HTML5Backend} context={window}>

@Luooojunnn
Copy link

add props context={window}, it's solved my problem.

thx,dude!

@botxboom
Copy link

botxboom commented Dec 4, 2023

For people still struggling with this: the issue mostly seems to occur when you wrap your DnD enabled component directly with a DnDProvider (instead of using the Provider at the top level of your app) and then navigating between routes/pages in your app.

I see two workarounds:

  • Wrap your top level <App> component with the <DnDProvider> and remove any other DnDProvider components. This ensures there can only ever be a single instance of the HTML5 backend.
  • Add the context={window} prop on the provider <DndProvider backend={HTML5Backend} context={window}>.

Hi @ekeijl , this context={window} resolves the issue. but why we have passed window? can we pass something else here?

@ekeijl
Copy link

ekeijl commented Dec 4, 2023

For people still struggling with this: the issue mostly seems to occur when you wrap your DnD enabled component directly with a DnDProvider (instead of using the Provider at the top level of your app) and then navigating between routes/pages in your app.
I see two workarounds:

  • Wrap your top level <App> component with the <DnDProvider> and remove any other DnDProvider components. This ensures there can only ever be a single instance of the HTML5 backend.
  • Add the context={window} prop on the provider <DndProvider backend={HTML5Backend} context={window}>.

Hi @ekeijl , this context={window} resolves the issue. but why we have passed window? can we pass something else here?

My guess is that context can be any globally available object (like window), but I have not tried it.

@dannobytes
Copy link

dannobytes commented Apr 8, 2024

add props context={window}, it's solved my problem.

Amazing, this worked for me too! Thank you @ymh1028

The docs are pretty terrible and outdated. So it's probably unlikely they'll be updated to include this, but at least this workaround exists.

Wrap your top level component with the and remove any other DnDProvider components. This ensures there can only ever be a single instance of the HTML5 backend.

This approach probably would work if you didn't have multiple sections in your App to have independent DnD interactions. In my case, we don't ever want a single DnD provider. We have multiple widgets within our App that all have their own DnD capabilities that shouldn't cross boundaries into other DnD areas.

So I wouldn't recommend this as a potential solution here b/c it shouldn't be the case to have only a single dnd provider at the root.

@whqgo
Copy link

whqgo commented May 7, 2024

image

I did it.

@adduss
Copy link

adduss commented Jul 1, 2024

image

I did it.

Using random number as key can really impact performance. For React reconciliation algorithm it will be new component on each render and it will recreate it, instead of reuse existing one, and probably that is why it works for you.

@akoskovacs
Copy link

This and other proposed solutions are still breaking Next.js apps. Unfortunately, the window might not be defined (if running on the server side) and you can't use use client in the main application component if something depends on server functionality (also that would transform the application into an SPA, then why even use Next.js).

egabancho added a commit to egabancho/invenio-rdm-records that referenced this issue Oct 29, 2024
* If the context is not set to window we can end up in a situation where
  multiple backends are instantiated resulting in an error. More info
  react-dnd/react-dnd#3257
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