javascript bootstrap - Verwenden von JQuery-Plugins, die das DOM in React Components transformieren?




github example (5)

Einige JQuery-Plugins fügen DOM-Knoten nicht nur Verhalten hinzu, sondern ändern sie auch. Zum Beispiel wird Bootstrap Switch gedreht

<input type="checkbox" name="my-checkbox" checked>

in etwas wie

<div class="bootstrap-switch bootstrap-switch-wrapper bootstrap-switch-on bootstrap-switch-large bootstrap-switch-animate">
  <div class="bootstrap-switch-container">
    <span class="bootstrap-switch-handle-on bootstrap-switch-primary">ON</span>
    <label class="bootstrap-switch-label">&nbsp;</label>
    <span class="bootstrap-switch-handle-off bootstrap-switch-default">OFF</span>
    <input type="checkbox" name="download-version" checked="" data-size="large" data-on-text="3" data-off-text="2.0.1">
  </div>
</div>

mit

$("[name='my-checkbox']").bootstrapSwitch();

Was nicht mit React übereinstimmt:

Uncaught Error: Invariant Violation: findComponentRoot(..., .0): Unable to find
element. This probably means the DOM was unexpectedly mutated (e.g., by the
browser), usually due to forgetting a <tbody> when using tables or nesting <p> or
<a> tags. ...<omitted>...`. 

Gibt es eine empfohlene Technik für die Einbindung dieser Plugins in React-Komponenten? Oder brechen sie die Annahmen von React grundlegend und können damit nicht arbeiten?


Answers

Nein, reagieren reagieren (haha) schlecht auf etwas, das seine eigene Komponente dom Struktur außerhalb reagiert. Das ist etwas, was du niemals tun willst. Die empfohlene Lösung wäre, die Funktionalität von was auch immer Sie versuchen, mit einem jquery oder einem ähnlichen Plugin zu replizieren.

Allerdings gibt es einen vernünftigen Weg, dies für bestimmte Fälle zu tun, in denen Sie einfach nicht ohne sie auskommen können, aber es bedeutet im Wesentlichen, einige nicht reagierende Domänen in Reaktion zu bringen.

Beispiel:

var Example = React.createClass({
    componentDidMount: function() {
        var $checkboxContainer = $(this.refs.checkboxContainer.getDOMNode());

        var $checkbox = $('<input />').prop('type', 'checkbox');

        $checkboxContainer.append($checkbox);

        $checkbox.bootstrapSwitch({});
    },
    render: function() {
        return (
            <div>
                <div ref="checkboxContainer"></div>
            </div>
        )
    }
});

Jetzt rendern Sie natürlich eine Komponente mit einem verschachtelten Div. Der verschachtelte, wenn er zum ersten Mal in das dom gemounted wird, erhält von jquery ein Ankreuzfeld, das dann auch unser jquery-Plugin darauf ausführt.

Diese spezielle Beispielkomponente hat wenig Sinn, aber Sie können sehen, wie sich dies in eine komplexere Komponente integrieren lässt, während Sie weiterhin auf Zustandsänderungen usw. rendern und reagieren können. Sie verlieren nur die Fähigkeit, direkt auf Ereignisse zu reagieren / zu modifizieren Dinge innerhalb der Checkbox in Frage, die, was die Reaktion betrifft, nicht existiert.

Wenn Sie nun mit dem obigen Beispiel eine Reaktivlogik zum Hinzufügen / Entfernen des verschachtelten Divs hätten, müssten Sie dieselbe Logik dafür haben, dass das eingefügte Div-Element dafür verantwortlich ist, das Checkbox-Kästchen wieder einzufügen und es erneut zu initialisieren jquery-Plugin. Da reactive das dom jedoch nur bei Bedarf ändert, wird dieser eingefügte dom-Inhalt nicht entfernt, es sei denn, Sie tun etwas, das das Container-div so verändert, dass es in dom entfernt / erneut gerendert wird. Dies bedeutet, dass Sie immer noch auf alle Ereignisse zugreifen können, die in diesem Container div usw. enthalten sind.

Sie können auch die componentDidMount Funktion verwenden, um auf Ereignisse oder Rückrufe zu bestimmten Interaktionen im Kontrollkästchen selbst zu reagieren. Stellen Sie sicher, dass Sie sie in componentWillUnmount oder wo immer es sinnvoll ist, in Ihrem spezifischen Fall im componentWillUnmount korrekt zu lösen.


In diesem großartigen Tutorial von ryanflorence erhalten Sie eine Idee, wie Sie dies tun können:

Wrapping DOM-Bibliotheken

Methodik

  1. DOM-Bibliotheken manipulieren normalerweise das DOM
  2. Reagieren versucht erneut zu rendern und findet ein anderes DOM als das letzte Mal und flippt aus
  3. Wir verstecken die DOM-Manipulation von React, indem wir die Rendering-Struktur unterbrechen und uns dann erneut um das DOM, das die lib manipuliert, verbinden.
  4. Verbraucher unserer Komponente können im React-Land bleiben.

Dies ist eher eine philosophische Frage

React wurde erstellt, um DOM-Manipulationen zu optimieren, und verfügt im Hintergrund über viel Aufwand, wenn der Status einer Komponente über setState geändert wird

Dies führt dazu, dass die Verdrahtung das virtuelle DOM durchquert, um die Knoten zu finden, die aktualisiert werden müssen

Wenn Sie React verwenden müssen, um zu versuchen, ein gewisses Maß an Konsistenz in Ihrem Code zu bewahren, ist es am besten, die JQuery-DOM-Manipulation im componentDidMount wie folgt anzuwenden ...

    componentDidMount(){
        this.node = $("#"+this.props.id); // Keep a reference to the node
        this.chart = this.node.easyPieChart(); // Apply JQuery transformation and keep a reference
        this.percentTitle = this.chart.find(".percent"); // Keep a reference to the title
    }

Haben Sie dies getan, egal was Ihre "refresh" -Methode ist, rufen Sie KEINE Aufrufe von setState auf, rufen Sie stattdessen die Update-Methode auf, die Ihre JQuery-Komponente haben könnte, so ...

        componentWillMount(){
            this.interval = setInterval(this._doRefresh.bind(this), 1500);
        }

        _doRefresh( percentage ){
            // Note how setState is NOT being called here
            percentage = percentage || Math.floor (Math.random() * 100) // simulate since we're not getting it yet
            this.chart.data('easyPieChart').update(percentage); // call easyPieChart's update
            this.percentTitle.text(percentage);
        }

An dieser Stelle, wenn Sie fragen, warum überhaupt Reagieren, gut, in meinem Fall, diese Komponente ist ein Element in einer Liste von anderen React-Komponenten und wurde verwendet, um Konsistenz in der gesamten Anwendung zu erhalten ... Sie können eine ähnliche haben Dilemma

Wenn Sie, im Gegensatz zu mir, Pech haben, dass Ihre Komponente keine Update-Methode hat und Sie keine erstellen können, ist es vielleicht an der Zeit, den Ansatz zu überdenken


Sicher, es gibt eine solche Technik. Wir machen diese Dinge die ganze Zeit.

  1. Sie erstellen die React-Komponente, um das jQuery-Plugin zu umbrechen.
  2. Innerhalb von render() Sie einen leeren <div ref="placeholder" />
  3. In Ihrer componentDidMount-Methode rufen Sie dieses Element mit ref auf und initialisieren das jQuery-Plugin dort.
  4. In Ihrer componentWillUnmount bereinigen Sie es. Aufruf von "destroy" oder etwas anderes, das benötigt wird, um Speicherlecks zu vermeiden.

Das ist es. Glücklicherweise ist es völlig ungefährlich, DOM auf diese Weise in React zu modifizieren.

Wenn Sie möchten, dass dieses Plugin auf Requisitenänderungen reagiert, werden die Dinge etwas komplizierter. Sie müssen andere Lifecycle-Methoden wie componentWillReceiveProps überschreiben, überprüfen, wann Requisiten sich tatsächlich geändert haben, und entsprechende Plug-in-Methoden aufrufen. Ich kann ausführlicher erklären, wenn Sie spezifische Fragen haben, ist das Thema zu breit für den Kommentar.


Wir können elementObject mit jQuery verwenden, um das Attribut zu prüfen:

$(objectElement).attr('checked');

Wir können dies für alle jQuery-Versionen ohne Fehler verwenden.

Update: Jquery 1.6+ hat die neue prop-Methode, die attr ersetzt, zB:

$(objectElement).prop('checked');




javascript jquery reactjs