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

DragSource attempting to setup HTML5Backend a second time in v9.4.0 #1558

Open
pjgates opened this issue Oct 1, 2019 · 9 comments
Open

DragSource attempting to setup HTML5Backend a second time in v9.4.0 #1558

pjgates opened this issue Oct 1, 2019 · 9 comments

Comments

@pjgates
Copy link

pjgates commented Oct 1, 2019

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)
@Enigma10
Copy link

Enigma10 commented Oct 14, 2019

I am also having same issue. #1571

@ozzyogkush
Copy link

ozzyogkush commented Dec 9, 2019

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

@darthtrevino
Copy link
Member

@ozzyogkush Maybe you can try using a single DndProvider mounted at the root of your app - there should only be one per document.

@ozzyogkush
Copy link

ozzyogkush commented Dec 10, 2019

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.

@Madhu94
Copy link

Madhu94 commented Mar 13, 2020

@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 ?)

@RavenColEvol
Copy link

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

@darthtrevino
Copy link
Member

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

@FontEndArt
Copy link

@pjgates我不知道这个想法有多糟糕,但您可以通过在挂载时将属性设置为 false 来使其工作。

useLayoutEffect(() => {
   window.__isReactDndBackendSetUp = false;
}, [])

我对 react dnd 的工作知之甚少,我想获得有关这种方法的反馈,无论这是否会破坏代码。

11.1.3 我临时选择了这种方法,期待更好的办法,可能需要用升级版本才可以?

@MeetzhDing
Copy link

[HTML5BackendImpl.ts#L108-L108](

public setup(): void {
const root = this.rootElement as RootNode | undefined
if (root === undefined) {
return
}
if (root.__isReactDndBackendSetUp) {
throw new Error('Cannot have two HTML5 backends at the same time.')
}
root.__isReactDndBackendSetUp = true
this.addEventListeners(root)
}
)

maybe this rootElement can be replace by ReactRef?
I cant use custom rootElement when my component is not mounted.

@darthtrevino

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

No branches or pull requests

8 participants