DragSource attempting to setup HTML5Backend a second time in v9.4.0
Describe the bug
After updating to v9.4.0 we found that when mounting components using the DragSource decorator, it would sometimes attempt to setup the HTML5Backend again, thus triggering the error Uncaught Error: Cannot have two HTML5 backends at the same time (as this.window.__isReactDndBackendSetUp was not false).
The Dnd Context Provider is declared in the root of the page (and thus is above the components that are unmounted and mounted in the tree).
I suspect that either the teardown isn't triggering when it should, or the setup is triggering when it shouldn't, thus triggering this error.
Also, it should be noted that having multiple DragSources (such as items in a list), doesn't trigger this when they're rendered together. It's only when the list is replaced with another list that this bug is triggered.
Expected behaviour
We expect that unmounting and mounting two components that use react-dnd to correctly update the this.window.__isReactDndBackendSetUp global variable without throwing an error.
Desktop (please complete the following information):
- OS: macOS (although this has been reported on other systems as well)
- Browser: Chrome
- Version: 77
Additional context The stack trace from console:
Uncaught Error: Cannot have two HTML5 backends at the same time.
at HTML5Backend.setup (HTML5Backend.js:388)
at DragDropManagerImpl.handleRefCountChange (DragDropManagerImpl.js:48)
at Object.dispatch (redux.js:227)
at HandlerRegistryImpl.addSource (HandlerRegistryImpl.js:100)
at registerSource (registration.js:13)
at DragDropContainer.receiveType (decorateHandler.js:154)
at DragDropContainer.receiveProps (decorateHandler.js:139)
at DragDropContainer.componentDidMount (decorateHandler.js:115)
at commitLifeCycles (react-dom.development.js:20049)
at commitLayoutEffects (react-dom.development.js:22813)
I am also having same issue. https://github.com/react-dnd/react-dnd/issues/1571
I am running into this type of issue as well, in my case I have some set of components mounted that uses react-dnd, and then say I open a modal with another type of component that also uses react-dnd and is wrapped with its own DndProvider, I encounter this error. Without wrapping the component I encounter other errors such as invariant found, etc. where it can't set up the drag/drop context.
On react-dnd and react-dnd-html5-backend versions 9.5.1
@ozzyogkush Maybe you can try using a single DndProvider mounted at the root of your app - there should only be one per document.
I found a temp. solution that works as such:
in my app index file:
const renderApp = () => {
ReactDOM.render(
<DndProvider backend={HTML5Backend}>
<App />
</DndProvider>,
document.getElementById('app-wrapper')
);
}
futher down the component tree...
<DndContext.Consumer>
{({ dragDropManager }) => {
return <MyComponent dragDropManager={dragDropManager} />;
}}
</DndContext.Consumer>
In my component defined in an external package:
function DndConsumerWithFallback({ dragDropManager, children }) {
return dragDropManager === undefined ?
<DndProvider backend={HTML5Backend}>{children}</DndProvider> :
<DndProvider manager={dragDropManager}>{children}</DndProvider>;
}
function MyComponent({ dragDropManager, ...componentProps }) {
return (
<DndConsumerWithFallback dragDropManager={dragDropManager}>
<SomeDragAndDroppableStuff {...componentProps} />
</DndConsumerWithFallback>
);
}
This way, if the app doesn't provide the manager, it falls back on a default.
@darthtrevino is the expectation that once the dnd provider component is mounted, it should never unmount ? (i.e. can it mount and unmount and re-mount ?)
@pjgates I don't know how bad this idea is but you can make it work by setting yourself the property to false on mount.
useLayoutEffect(() => {
window.__isReactDndBackendSetUp = false;
}, [])
I don't have much knowledge about working of react dnd and I would like to get feedback on this approach wether this will break code or not.
The DndProvider break down the HTML5Backend when it is unmounted, and the HTML5Backend will clear that variable in the window.
That being said, all of the testing of this library has been done with a stable root DndProvider in the sample apps
@pjgates我不知道这个想法有多糟糕,但您可以通过在挂载时将属性设置为 false 来使其工作。
useLayoutEffect(() => { window.__isReactDndBackendSetUp = false; }, [])我对 react dnd 的工作知之甚少,我想获得有关这种方法的反馈,无论这是否会破坏代码。
11.1.3 我临时选择了这种方法,期待更好的办法,可能需要用升级版本才可以?
[HTML5BackendImpl.ts#L108-L108](https://github.com/react-dnd/react-dnd/blob/8e6f62e612c0b0a376ac4a86cd371588dfcd2a70/packages/backend-html5/src/HTML5BackendImpl.ts#L101-L112)
maybe this rootElement can be replace by ReactRef? I cant use custom rootElement when my component is not mounted.
@darthtrevino