React-dnd: Es können nicht zwei HTML5-Backends gleichzeitig vorhanden sein

Erstellt am 8. Juni 2015  ·  62Kommentare  ·  Quelle: react-dnd/react-dnd

Hallo Dan,

Nur eine kurze - ich versuche, meine eigene Komponente mit react-dnd als Abhängigkeit in einer anderen App zu verwenden, die selbst react-dnd sodass der oben genannte Fehler erwartet wird. Was wäre in diesem Fall der beste Weg, dies zu beheben?

Da die andere Komponente meine eigene ist, kann ich den Aufruf von DragDropContext beim Exportieren der Komponente entfernen, was jedoch die Wiederverwendbarkeit der Komponente beeinträchtigt. Was raten Sie?

Hilfreichster Kommentar

Ein anderer Ansatz, der etwas sauberer ist, besteht darin, ein Modul zu erstellen, das den Dekorator für ein bestimmtes Backend generiert, und dann den Dekorator bei Bedarf zu verwenden:

lib / withDragDropContext.js

import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

export default DragDropContext(HTML5Backend);

components / MyComponent.js

import { Component } from 'react';
import withDragDropContext from '../lib/withDnDContext';

class MyComponent extends Component {

  render() {
    return (
     <div>
       // other children
     </div>
   );
}

export default withDragDropContext(MyComponent);

Alle 62 Kommentare

Überprüfen Sie die Quelle für DragDropContext . Ich denke, Sie sollten in der Lage sein, den vorhandenen Manager wiederzuverwenden, wenn er von einer Komponente über dem Baum angegeben wird. Aber es ist immer noch eine knifflige Frage. Haben Sie Lösungsvorschläge?

Ich denke, Sie sollten in der Lage sein, den vorhandenen Manager wiederzuverwenden, wenn er von einer Komponente über dem Baum angegeben wird.

Selbst wenn dies möglich ist, sollte die exportierte Komponente auch unabhängig arbeiten können. In Fällen, in denen das Backend vorhanden ist (in der App, in der die Komponente verwendet wird), sollte irgendwo in der Kette wiederverwendet werden. Ich werde versuchen, die Quelle zu lesen und zu sehen, ob dies durchgeführt werden kann.

Leider besteht die einzige Lösung, die mir derzeit einfällt, darin, die endgültige Komponente so zu exportieren, wie sie ist, und vom Benutzer zu erwarten, dass er ein DragDropContext mit einem Backend seiner Wahl hinzufügt. Was denken Sie?

Die exportierte Komponente sollte auch unabhängig arbeiten können. In Fällen, in denen das Backend vorhanden ist (in der App, in der die Komponente verwendet wird), sollte irgendwo in der Kette wiederverwendet werden.

Ja, dies ist möglich, indem Sie DragDropContext insgesamt verwenden und stattdessen manuell dragDropManager im Kontext verwenden. Ihre Komponente kann in den Kontext schauen und entweder die vorhandenen dragDropManager im Kontext weitergeben oder einen eigenen erstellen. Es scheint jedoch etwas zerbrechlich.

Leider besteht die einzige Lösung, die mir derzeit einfällt, darin, die endgültige Komponente so zu exportieren, wie sie ist, und vom Benutzer zu erwarten, dass er einen DragDropContext mit einem Backend seiner Wahl hinzufügt. Was denken Sie?

Ich denke, das ist die flexibelste Lösung. Sie können sich dort auch eine Meinung bilden und <MyComponentContext> exportieren, für die DragDropContext(HTML5Backend) .

Exportieren Sie <MyComponentContext> , das DragDropContext(HTML5Backend)

Es tut mir leid, ich verstehe das nicht ganz. Können Sie das etwas näher erläutern?

export default function MyTagControlContext(DecoratedClass) {
  return DragDropContext(HTML5Backend)(DecoratedClass);
}

und Sie können Benutzer anweisen, entweder ihre Komponente der obersten Ebene in MyTagControlContext zu verpacken oder DragDropContext direkt zu verwenden, wenn sie bereits React DnD verwenden.

Ah! Wie wäre es damit? Sieht das zu hässlich aus?

// in main component file
module.exports = {
    WithContext: DragDropContext(HTML5Backend)(ReactTags),
    WithOutContext: ReactTags
};

Die Nutzung kann dann so etwas wie sein

var ReactTags = require('react-tags').WithContext; // if your app doesn't use react-dnd
var ReactTags = require('react-tags').WithOutContext; // if your app already uses react-dnd.

Ich glaube nicht, dass dies funktionieren würde, da jedes <ReactTags> eine eigene Kopie des Backends erhalten und zu dem oben eingefügten unveränderlichen Fehler führen würde, da diese Backends dieselben globalen Fensterereignisse behandeln.

Was meiner Meinung nach funktionieren wird, ist, dass Sie dragDropManager manuell erstellen können (genau wie DragDropContext intern) und dieselbe Instanz für alle ReactTag Instanzen verwenden können - mit einem Fallback auf die Manager definiert in context .

Ich meine, so etwas aus Ihrer Bibliothek zu exportieren:

let defaultManager;
function getDefaultManager() {
    if (!defaultManager) {
        defaultManager = new DragDropManager(HTML5Backend);
    }
    return defaultManager;
}

class ReactTagContext {
    static contextTypes = {
        dragDropManager: PropTypes.object.isRequired
    };

    static childContextTypes = {
        dragDropManager: PropTypes.object.isRequired
    };

    getChildContext() {
        return {
            dragDropManager: this.context.dragDropManager || getDefaultManager()
        };
    }

    render() {
        return <ReactTag {...props} />
    }
}

Vielen Dank, Dan! Ich werde das ausprobieren und mich bei Ihnen melden. Vielen Dank, dass Sie den Code geteilt haben: grinsend:

Kein Problem. Wenn Sie dies so tun, exportieren Sie einfach diese Klasse, anstatt ReactTags direkt zu exportieren. Es sollte "wie es ist" ohne Wrapper oder Dekorateure verwendbar sein.

Also Dan! Zum Teufel habe ich oben die Lösung für mehrere Exporte

// in main component file
module.exports = {
    WithContext: DragDropContext(HTML5Backend)(ReactTags),
    WithOutContext: ReactTags
};

In meiner anderen App habe ich versucht , die Komponente ohne Kontext zu und zu meiner großen Freude scheint sie gut zu funktionieren!

Denken Sie, dass dies eine hackige Lösung ist und ich sollte mit dem fortfahren, was Sie vorgeschlagen haben, oder sollte ich dies zulassen?

@ prakhar1989 Sind Sie sicher, dass dies mit mehreren <Tags /> auf der Seite funktioniert?

Du hattest mich für eine Sekunde dort! : stick_out_tongue:

img

Zum Glück funktioniert es!

Hmm, dann ist es vielleicht in Ordnung ;-). Lassen Sie mich wissen, wenn Sie Probleme mit diesem Ansatz haben!

Wird besorgt! Nochmals vielen Dank für all Ihre Hilfe.

PS: Haben Sie bessere Benennungsideen für WithContext und WithoutContext ?

@ prakhar1989 Ich würde wahrscheinlich nur die Version WithContext direkt exportieren und NoContext als statisches Feld darauf setzen.

Ich stoße auf ein ähnliches Problem und möchte besser verstehen, warum diese Einschränkung überhaupt besteht, da das Schreiben wiederverwendbarer Komponenten dadurch ziemlich schwierig wird. So wie es ist, muss jede Komponente, die react-dnd verwendet, verschiedene Kontexte kennen, die in der Anwendung vorhanden sein können, und diese entsprechend behandeln. Es wäre vorzuziehen, wenn jede Komponente ihr eigenes Drag-Verhalten / ihren eigenen Kontext verwalten könnte, unabhängig davon, was im Rest der Anwendung sonst noch vor sich geht.

Zum Beispiel möchte ich vielleicht einen Anwendungsbildschirm mit mehreren Komponenten zum Hochladen von Dateien, einem sortierbaren Menü und einem Spiel mit ziehbaren Elementen. Jede dieser Komponenten hat sehr unterschiedliche Möglichkeiten, mit Drag-Ereignissen umzugehen, und sollte wirklich für ihren eigenen Kontext verantwortlich sein.

Meine erste Frage ist, warum dies nicht einfach im HTML5Backend-Code geschieht.

setup() {
    ...

    // Events already setup - do nothing
    if (this.constuctor.isSetUp) return;

    // Don't throw an error, just return above.
    //invariant(!this.constructor.isSetUp, 'Cannot have two HTML5 backends at the same time.');

    this.constructor.isSetUp = true;
    ...
  }

Warum nicht einfach im HTML5Backend-Code?

Das ist ein großartiger Punkt. Wenn die Komponente mehrere Backends erkennen kann, kann sie dann nicht direkt die Logik haben, auf das vorhandene Backend im Gültigkeitsbereich zurückzugreifen?

Hallo @gaearon, ich DragDropContext was diesen Fehler verursacht. Ich habe versucht, dem obigen Thread zu folgen, aber mir ist nicht ganz klar, was ich tun kann, damit diese separaten Reaktionskomponenten einen Kontext gemeinsam nutzen, ohne alles andere auf meiner Seite in "Reagieren" zu konvertieren (nicht ideal). Ich bin ein bisschen mit der ES6-Syntax vertraut, arbeite aber an einem Projekt, das noch ES5 verwendet. Gibt es eine Möglichkeit, das gemeinsame Konzept von DragDropManager von oben anzuwenden? Ich habe es bisher versucht und ich habe anscheinend keinen Zugriff auf DragDropManager da es in dnd-core

Vielen Dank für Ihre Hilfe und für diese tolle Bibliothek!

PS Wenn es darauf ankommt, verwende ich ngReact.

@ prakhar1989 @globexdesigns @gaearon

Ich frage mich das Gleiche, warum HTML5-Backend das Backend nicht einfach wiederverwenden kann, wenn mehrere verwendet werden. Laut meinem vorherigen Kommentar macht dies React-Dnd für mich wirklich unbrauchbar, da ich mehrere Reaktionsbereiche innerhalb einer eckigen Seite habe, die in der Lage sein müssen, DnD untereinander auszuführen, und damit gegen eine Wand stoße.

Hat jemand eine schnelle Lösung dafür? Ich bin in meiner Entwicklung an einem toten Punkt angelangt.

@abobwhite So habe ich es gelöst. Es ist definitiv keine großartige Lösung, aber es scheint ab sofort zu funktionieren.

Hoffe das hilft,

Danke, @ prakhar1989 ! Aber ich verfolge nicht, wie der Mehrfachexport mit einem mit Kontext umhüllten und einem das Problem nicht löst. Mein Problem besteht darin, dass ich möglicherweise nicht mit react-dnd in eine andere Anwendung eingebettet werde, sondern nicht in der Lage bin, meinen gesamten dnd-fähigen Bereich (mit mehreren reaktions- und eckigen Komponenten / Anweisungen) in reag zu verpacken, sodass ich versucht habe, den Kontext nur um diese zu wickeln Reagiere auf Komponenten auf meiner Seite, die DnD unterstützen ... Ich würde gerne den Ansatz von @gaearon von oben ausprobieren, aber ich habe keinen Zugriff auf die DragDropManager um eine neue zu erstellen ...

Ich habe genau das gleiche Problem. Ich stimme @abobwhite voll und ganz zu, dass dadurch Komponenten weniger wiederverwendbar werden.

Dieser Thread hat mich dazu gebracht, mein unveränderliches Problem zu lösen, indem ich die HTML5Backend und DragDropContext in meiner Komponentenhierarchie nach oben verschoben habe, genau wie in den Dokumenten empfohlen .

Das ist ein komisches Problem. Ich arbeite an einer verschachtelten nachbestellbaren Komponente und habe DragDropContext in der übergeordneten Komponente verschachtelt. Es scheint eigenständig zu funktionieren (aber es hat immer noch verschachtelten DragDropContext).

Wenn ich diese Komponente jedoch in einem anderen Projekt verwende, in dem DragDropContext über der Hierarchie initialisiert wurde, wird dieser Fehler angezeigt.

Ich bin auf dieses Problem mit einer Anwendung gestoßen, an der ich arbeite. Ich hatte die volle Kontrolle über alle Komponenten, also habe ich statt @DragDropContext(HTMLBackend) etwas verwendet, das dem @gaearon- Code in diesem Kommentar sehr nahe kommt , um ein decorator zu erstellen, das einen gemeinsamen Widerstand ergibt Kontext löschen. Es funktioniert wirklich gut.

Mir ist gerade das Gleiche passiert und das Problem war, dass ich ComponentA hatte, das @DragDropContext(HTMLBackend) und dann ComponentB, das auch @DragDropContext(HTMLBackend) .

ComponentB wurde in ComponentA importiert, was den Fehler für mich verursacht hat. Alles was ich tun musste war den DragDropContext aus ComponentB zu entfernen und es funktionierte.

Was ist, wenn die App 2 DrapDropContext , diese jedoch nicht Eltern und Kind sind?

Mein Fall:

  1. Initialisieren Sie den ersten und den Kontext
  2. Initialisieren Sie als Geschwister einen zweiten dnd Kontext. 💣

Ich kann childContext nicht überprüfen, da die zweite Komponente kein untergeordnetes Element der ersten dnd-Komponente / des ersten dnd-Kontexts ist

Um mein Problem zu lösen, habe ich einen Singleton mit diesem Code erstellt:

import { DragDropManager } from 'dnd-core';
import HTML5Backend from 'react-dnd-html5-backend';

let defaultManager;

/**
 * This is singleton used to initialize only once dnd in our app.
 * If you initialized dnd and then try to initialize another dnd
 * context the app will break.
 * Here is more info: https://github.com/gaearon/react-dnd/issues/186
 *
 * The solution is to call Dnd context from this singleton this way
 * all dnd contexts in the app are the same.
 */
export default function getDndContext() {
  if (defaultManager) return defaultManager;

  defaultManager = new DragDropManager(HTML5Backend);

  return defaultManager;
}

Und dann entferne ich in allen Komponenten, die ein Kind haben, das DragDropContext(HTML5Backend) , es von diesem Kind und in ihren Eltern mache ich Folgendes:

import getDndContext from 'lib/dnd-global-context';

const ParentComponent = React.createClass({

  childContextTypes: {
    dragDropManager: React.PropTypes.object.isRequired,
  },

  getChildContext() {
    return {
      dragDropManager: getDndContext(),
    };
  },

  render() {
    return (<ChildComponentWithDndContext />);
  },

Ich denke, der Schlüssel ist, dass ich den Kontext dnd nur einmal initialisiere. Was denken Sie?

@andresgutgon danke. Das funktioniert auch bei mir

@andresgutgon Ihre Lösung ist großartig, aber es ist seltsam, dass DrapDropContext DragDropManager auf componentWillUnmount , dh wenn Sie keine 2 DrapDropContext s verwenden zur gleichen Zeit, sondern auf 2 verschiedenen Seiten - Sie können sie immer noch nicht verwenden. Ich werde Ihren Hack in meinem Fall versuchen, aber es ist immer noch 100% seltsam, Hacks für solch eine triviale Situation zu haben.

Auch eine Idee, warum 2 DragDropManager etwas Schlechtes / Falsches in react-dnd ?

Ein anderer Ansatz, der etwas sauberer ist, besteht darin, ein Modul zu erstellen, das den Dekorator für ein bestimmtes Backend generiert, und dann den Dekorator bei Bedarf zu verwenden:

lib / withDragDropContext.js

import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

export default DragDropContext(HTML5Backend);

components / MyComponent.js

import { Component } from 'react';
import withDragDropContext from '../lib/withDnDContext';

class MyComponent extends Component {

  render() {
    return (
     <div>
       // other children
     </div>
   );
}

export default withDragDropContext(MyComponent);

Hallo, weiß jemand, wie man löst, wenn Sie eine Komponente in DragDropContext und dann eine andere Komponente, die ebenfalls DragDropContext verwendet, eingewickelt haben, aber diese Komponente (großer Kalender reagieren) ist ein npm-Paket, also entfernen Sie es von dort gibt es keine Lösung und sie sind nebeneinander, nicht Eltern-Kind ... Sie können hier einen Blick darauf werfen https://github.com/martinnov92/TSCalendar (es ist in Arbeit - es ist also ein bisschen chaotisch: D) Danke

Ich glaube, ich habe genau das gleiche Problem mit der Verwendung des React-Mosaic- Kachel-Fenstermanagers, der React-Dnd verwendet, und meiner eigenen Komponenten, die auch React-Dnd verwenden.

Ich vermute, dass dies nicht direkt in React-Dnd gelöst wurde, aber es gibt einige Problemumgehungen, die wir anwenden können.

Gibt es ein Beispiel für einen vollständigen Arbeitscode, der dieses Problem behebt?

Die Lösung von @gcorne funktioniert

Hallo, ich habe das gleiche Problem, aber wir verwenden das React-Data-Grid und versuchen, den React-Big-Kalender hinzuzufügen
Nach dem Hinzufügen einer Komponente, die den React-Big-Kalender enthält, wird der Fehler "Nicht erfasster Fehler: Es können nicht zwei HTML5-Backends gleichzeitig vorhanden sein" angezeigt.

React-Big-Kalender Verwenden Sie React-Dnd und React-Dnd-HTML5-Backend. Wie kann dieses Problem gelöst werden?

Hallo @szopenkrk, haben Sie diese https://github.com/react-dnd/react-dnd/issues/186#issuecomment -232382782 ausprobiert?
Aber ich denke, Sie müssten eine Pull-Anfrage stellen, um auf einen großen Kalender zu reagieren und ein Dnd-Backend zu akzeptieren

Wahrscheinlich etwas zu spät, aber ich habe eine ähnliche, aber etwas andere Lösung gefunden. Ich habe eine Komponente höherer Ordnung implementiert und verwende sie einfach in allen meinen DragDropContext-fähigen Komponenten.

Code sieht folgendermaßen aus (TypeScript):

import * as React from 'react';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

// context singleton
let context: Function;

export function withDragDropContext<P>(
    Component: React.ComponentClass<P> | React.StatelessComponent<P>,
): React.ComponentClass<P> {
    // ensure a singleton instance of the context exists
    if (!context) {
        context = DragDropContext<P>(HTML5Backend);
    }

    return context(Component);
}

Und verwenden Sie es dann wie folgt in Ihren Komponenten:

import * as React from 'react';
import {withDragDropContext} from 'components/WithDragDropContext';

class MyClass extends React.Component<IMyClassProps, {}> {
    // ...
}

export default withDragDropContext<IMyClassProps>(MyClass);

NB
Ich habe es noch nicht versucht, aber Sie sollten wahrscheinlich in der Lage sein, die Kontextvariable während der Deklaration zu füllen:

const context = DragDropContext(HTML5Backend);

und überspringen Sie dann den Teil if (!context) {... .

@codeaid Danke!

Ich habe die gleiche Situation wie @andresgutgon getroffen , konnte sie aber mit seiner Methode und all der Methode, die ich hier ausprobiert

Warum hat @ guang2013 hier keine der Lösungen

Nein, immer noch keine Lösungen, ich weiß nicht, ich habe versucht, die Karte in bigCalendar zu ziehen, und ich habe die Karte als dragSource und die Kartenliste als DragAndDropContext erstellt, den Kalender als einen weiteren DragAndDropContext, dann habe ich zwei html5backend-Fehler ausgegeben eine hier bereitgestellte Methode zu verwenden, aber niemand kann mein Problem lösen. @andresgutgon , wann bist du online, kann ich direkt mit dir darüber sprechen? Sehr geschätzt.

@ guang2013 Wenn Sie eine Bibliothek verwenden, die von DragDropContext von react-dnd abhängt, funktioniert diese Technik nicht, da die Bibliothek Ihren einheitlichen dndContext nicht verwendet. In einigen Bibliotheken wie dem React-Sortable-Tree können Sie die Komponenten ohne Kontext verwenden, sodass Sie sie jedoch selbst umbrechen können.

Die Lösung von @gcorne hat für mich funktioniert, um die Verwendung von react-dnd in einer App mit react-hot-loader zu ermöglichen. Trotzdem bin ich ein wenig überrascht, dass es nicht sofort funktioniert hat!

Altes Problem, aber falls jemand anderes von Google hier landet:

Ich hatte nur 1 DND-Anbieter auf meiner Seite, ich habe keine andere Bibliothek mit DND integriert, aber ich bin trotzdem auf diesen Fehler gestoßen, etwas zufällig.

Mein Problem war, dass sich der DragDropContextProvider im BrowserRouter-Element von ReactRouter befand, wodurch das HTML5Backend bei jeder Navigation rekonstruiert werden konnte und ob sowohl die alte Seite (von der weg navigiert wurde) als auch die neue Seite (zu der navigiert wurde) DND-Elemente hatte. Der obige Fehler würde auftreten.

Die Lösung bestand darin, den DragDropContextProvider aus BrowserRouter zu entfernen.

Dieser ist für diejenigen Sterblichen gedacht, die ReactDnD zum ersten Mal ausprobiert haben, dem Tutorial gefolgt sind und ein 64-Quadrat-Schachbrett erhalten haben.
Ich konnte meinen Ritter nach Belieben herumschleppen.
Das Problem war, als ich versuchte, es in einem der BoardSquare , warf es sich mit dem 2 HTML5-Backend-Problem auf.

Die Reparatur

Verschieben Sie, wie bereits in den Kommentaren erwähnt, das Rendering von DragDropContextProvider außerhalb des App-Rendering-Zyklus.
Führen Sie wie in nicht direkt ein ReactDOM.render als Rückruf für die Funktion observe aus.
Tun Sie stattdessen Folgendes:

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import './index.css';
import App from './App';

ReactDOM.render(
    <DragDropContextProvider backend={HTML5Backend}>
        <App />
    </DragDropContextProvider>,
    document.getElementById('root')
)

App.js

import React, { Component } from 'react';
import Board from './Board';
import { observe } from './Game';

class App extends Component {
    state = {
        knightPosition: [0, 0]
    }

    componentDidMount = () => {
        observe(knightPosition => {
            this.setState(prevState => ({
                ...prevState,
                knightPosition
            }));
        });
    }

    render() {
        return (
            <div className="App">
                <Board knightPosition={this.state.knightPosition} />
            </div>
        );
    }
}

export default App;

Ich denke, das hängt mit diesem Problem zusammen
https://github.com/prakhar1989/react-tags/issues/497

@gaearon Ich weiß, dass dies alt ist, aber wie kann ich in Ihrem Beispiel tatsächlich DragDropManager ? Es wird nirgendwo exportiert.

defaultManager = new DragDropManager(HTML5Backend);

Mein Problem ist, dass ich einige Widgets auf einer Seite über eine Drittanbieter-API rendere und DragDropContextProvider höher als mein eigentliches Widget verschieben kann.

Dieses Problem wurde durch Löschen des alten Builds behoben.
Löschen Sie einfach den dist-Ordner oder bearbeiten Sie index.html. Ich kenne das genaue Problem nicht, aber das hat bei mir funktioniert

Glücklicherweise konnte ich die (versteckte) Antwort von @gcorne finden (https://github.com/react-dnd/react-dnd/issues/186#issuecomment-282789420). Es löste mein Problem - das als schwierig angesehen wurde - sofort.
@ prakhar1989 Ich habe das Gefühl, dass es eine echte

Die Lösung, die ich herausgefunden habe, funktioniert für mich und ermöglicht mir die Verwendung von HTML5- oder Touch-Backend:

Erstellen Sie eine Singleton-HOC-Komponente:

import {DragDropContext} from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import TouchBackend from "react-dnd-touch-backend";

const DragAndDropHOC = props => {
    return <React.Fragment>
        {props.children}
    </React.Fragment>
};

export default {
    HTML5: DragDropContext(HTML5Backend)(DragAndDropHOC),
    Touch: DragDropContext(TouchBackend)(DragAndDropHOC),
}

Dann eine Anbieterkomponente:

const DragDrop = props => {
    if (props.isTouch) {
        return <DragDropContext.Touch>{props.children}</DragDropContext.Touch>
    } else {
        return <DragDropContext.HTML5>{props.children}</DragDropContext.HTML5>
    }
};

Und benutze <DragDrop isTouch={props.isTouch} /> wo immer ich es brauche.

Für Entwickler, die auf dasselbe Problem stoßen, können Sie sich diese HOC-Lösung ansehen

Ich stoße jetzt mit Jest-Tests auf dieses Problem. HTML5-Backend wird in den Jest-Tests wie ein Singleton behandelt (weshalb das Problem auftritt ... glaube ich).

Detailliertes Problem in SO:

https://stackoverflow.com/questions/58077693/multiple-react-dnd-jest-tests-cannot-have-two-html5-backends-at-the-same-time

Haken verwenden

import { createDndContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";

const manager = useRef(createDndContext(HTML5Backend));

return (
  <DndProvider manager={manager.current.dragDropManager}>
      ....
  </DndProvider>
)

Eine bessere Lösung mit Hooks (danke @jchonde):

import { DndProvider, createDndContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import React, { useRef } from "react";

const RNDContext = createDndContext(HTML5Backend);

function useDNDProviderElement(props) {
  const manager = useRef(RNDContext);

  if (!props.children) return null;

  return <DndProvider manager={manager.current.dragDropManager}>{props.children}</DndProvider>;
}

export default function DragAndDrop(props) {
  const DNDElement = useDNDProviderElement(props);
  return <React.Fragment>{DNDElement}</React.Fragment>;
}

dann können Sie also woanders verwenden:

import DragAndDrop from "../some/path/DragAndDrop";

export default function MyComp(props){
   return <DragAndDrop>....<DragAndDrop/>
}

Meine Lösung:
Stellen Sie sicher, dass die untergeordnete Komponente react-dnd direkt importiert.
Übergeben Sie die Komponenten DragDropContext und HTML5Backend von der übergeordneten an die untergeordnete Komponente.

Das Hinzufügen eines eindeutigen Schlüssels zum DragDropContextProvider-Tag löst das Problem <DragDropContextProvider backend={HTML5Backend} key={Math. random()}></DragDropContextProvider>

Im Typoskript habe ich die folgende Komponente erstellt. (danke @jchonde @ttessarolo )

import { DndProvider, createDndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import React, { PropsWithChildren, useRef } from 'react';

const RNDContext = createDndContext(HTML5Backend);

function DragAndDrop({ children }: PropsWithChildren<{}>): JSX.Element {
  const manager = useRef(RNDContext);
  return <DndProvider manager={manager.current.dragDropManager}>{children}</DndProvider>;
}

export default DragAndDrop;

Und eine Komponente wie diese verwendet

function SomeComponent(): JSX.Element {
  return (
    <DragAndDrop>
      ...
    </DragAndDrop>
  );
}

Das Hinzufügen eines eindeutigen Schlüssels zum DragDropContextProvider-Tag löst das Problem <DragDropContextProvider backend={HTML5Backend} key={Math. random()}></DragDropContextProvider>

Gut gemacht!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen