react-dnd icon indicating copy to clipboard operation
react-dnd copied to clipboard

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

Open dcsaszar opened this issue 4 years ago • 19 comments
trafficstars

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.

dcsaszar avatar Jul 14 '21 16:07 dcsaszar

+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)

ismailmmd avatar Aug 16 '22 10:08 ismailmmd

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

piechoo avatar Aug 30 '22 07:08 piechoo

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

ymh1028 avatar Sep 07 '22 11:09 ymh1028

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

Thanks you saved my ass

emileWhispa avatar Nov 04 '22 08:11 emileWhispa

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",

ZijieZh avatar Dec 12 '22 07:12 ZijieZh

should this context prop be documented somehow ?

aovchinn avatar Jan 25 '23 11:01 aovchinn

should this be true by default ? const isGlobalInstance = !props.context https://github.com/react-dnd/react-dnd/blob/7c88c37489a53b5ac98699c46a506a8e085f1c03/packages/react-dnd/src/core/DndProvider.tsx#L65

aovchinn avatar Jan 25 '23 11:01 aovchinn

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

thx,it works

echoyl avatar Feb 15 '23 07:02 echoyl

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",

clfuture avatar Apr 21 '23 01:04 clfuture

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

有用的!!!

coder-zhuzm avatar Oct 31 '23 09:10 coder-zhuzm

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}>.

ekeijl avatar Nov 14 '23 11:11 ekeijl

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

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

pvrameshkf avatar Nov 15 '23 09:11 pvrameshkf

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

thx,dude!

Luooojunnn avatar Nov 23 '23 02:11 Luooojunnn

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?

botxboom avatar Dec 04 '23 17:12 botxboom

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.

ekeijl avatar Dec 04 '23 19:12 ekeijl

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 <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.

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.

dannobytes avatar Apr 08 '24 19:04 dannobytes

image

I did it.

whqgo avatar May 07 '24 04:05 whqgo

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.

adduss avatar Jul 01 '24 10:07 adduss