Wie gehe ich von jQuery zu React.js? [geschlossen]

73

Ich habe jetzt seit ein paar Tagen über React gelesen. Ich kann das meiste verstehen, was ich sehe, aber ich bin nicht ganz sicher, ob ich es schreiben kann. Ich habe an einer kleinen Web-App gearbeitet, die die gesamte HTML-Generierung über jQuery durchführt und Elemente aneinander anfügt. Ich würde gerne versuchen, dies mit React wieder aufzubauen, weil ich glaube, dass es schneller sein würde. Diese JSFiddle ist ein kleines Beispiel für die Art von Dingen, an denen ich arbeite. Wie würden Sie es mit React schreiben?

JS:

function remove() {
    this.remove();
}

function timed_append_new_element() {
    setTimeout(function () {
        var added_content = $("<span />", {
            class: "added_content",
            text: "Click to close",
            click: remove
        });
        container.append(added_content);
    }, 3000);
}

function append_new_element() {
    var added_content = $("<span />", {
        class: "timed_added_content",
        text: "Click to close",
        click: remove
    });
    container.append(added_content);
}


var container = $("<div />", {
    class: "container"
});
var header = $("<span />", {
    class: "header",
    text: "jQuery to React.js Header"
});
var add_button = $("<button />", {
    class: "add_button",
    text: "Add Element",
    click: append_new_element
});
var timed_add_button = $("<button />", {
    class: "add_button",
    text: "Add Element in 3 seconds",
    click: timed_append_new_element
});
container.append(header);
container.append(add_button);
container.append(timed_add_button);
$("body").append(container);
Leicht verblüfft
quelle

Antworten:

173

Es sind einige grundlegende Grundsätze zu beachten, die Ihnen beim Erstellen einer guten React-Anwendung helfen können:

Ihre Benutzeroberfläche sollte eine Funktion der Daten sein

In vielen Anwendungen im "jQuery-Suppen" -Stil sind die Geschäftslogik für die Anwendung, die Daten der App und der Interaktionscode der Benutzeroberfläche miteinander vermischt. Dies macht es schwierig, diese Art von Anwendungen zu debuggen und insbesondere zu erweitern. Reagieren Sie wie bei vielen modernen clientseitigen Anwendungsframeworks die Idee, dass die Benutzeroberfläche nur eine Darstellung Ihrer Daten ist. Wenn Sie möchten, dass sich Ihre Benutzeroberfläche ändert, sollten Sie ein Datenelement ändern und zulassen, welches Bindungssystem das Framework verwendet, um die Benutzeroberfläche für Sie zu aktualisieren.

In React ist jede Komponente (idealerweise) eine Funktion von zwei Datenelementen - den an die Komponenteninstanz übergebenen Eigenschaften und dem Status , den die Komponente intern verwaltet. Bei gleichen Eigenschaften (oder "Requisiten") und demselben Status sollte die Komponente auf dieselbe Weise gerendert werden.

Dies kann eine abstrakte Idee ohne konkrete Beispiele sein. Denken Sie also daran, wenn wir vorerst weitermachen.

Berühren Sie nicht das DOM

In React sollten Sie noch mehr als in anderen datengebundenen Frameworks versuchen, das DOM nicht direkt zu manipulieren, wenn dies überhaupt möglich ist. Viele der Leistungs- und Komplexitätsmerkmale von React sind nur möglich, weil React intern ein virtuelles DOM mit unterschiedlichen Algorithmen verwendet, um das reale DOM zu bearbeiten. Jedes Mal, wenn Sie eine Komponente erstellen, die nach außen greift und ihre eigene DOM-Manipulation ausführt, sollten Sie sich fragen, ob Sie dieselbe Funktion idiomatischer mit den virtuellen DOM-Funktionen von React erstellen können.

Natürlich müssen Sie manchmal auf das DOM zugreifen oder ein jQuery-Plugin einbinden, ohne es in React neu zu erstellen. In Zeiten wie diesen bietet React Ihnen gute Hooks für den Lebenszyklus von Komponenten , mit denen Sie sicherstellen können, dass die Leistung von React nicht zu stark beeinträchtigt wird (oder in einigen Fällen, um zu verhindern, dass Ihre Komponente einfach bricht).

Das DOM nicht zu manipulieren, geht Hand in Hand mit "Benutzeroberfläche als Funktion der Daten" oben.

Invertieren Sie den Datenfluss

In einer großen React-Anwendung kann es schwierig sein, zu verfolgen, welche Unterkomponente ein bestimmtes Teil der Anwendungsdaten verwaltet. Aus diesem Grund empfiehlt das React-Team, die Datenmanipulationslogik an einem zentralen Ort aufzubewahren. Der einfachste Weg, dies zu tun, besteht darin, Rückrufe an untergeordnete Komponenten zu übergeben. Es gibt auch eine bei Facebook entwickelte Architektur namens Flux, die eine eigene Website hat .

Erstellen Sie zusammensetzbare Komponenten

Oft kann es verlockend sein, eine große Komponente zu schreiben, die mehrere Statuselemente oder mehrere Teile der UI-Logik verwaltet. Wenn möglich (und im Rahmen des Zumutbaren), sollten Sie in Betracht ziehen, größere Komponenten in kleinere zu unterteilen, die mit einem einzelnen Datenelement oder einer UI-Logik arbeiten. Dies erleichtert das Erweitern und Bewegen von Teilen Ihrer Anwendung erheblich.

Vorsicht vor veränderlichen Daten

Da der Komponentenstatus nur über Aufrufe this.setStatevon innerhalb der Komponente aktualisiert werden sollte , ist es hilfreich, sich vor veränderlichen Daten zu hüten. Dies gilt in zweifacher Hinsicht, wenn mehrere Funktionen (oder Komponenten!) Das veränderbare Objekt im selben Häkchen aktualisieren können. React versucht möglicherweise, Statusänderungen zu stapeln, und Sie können Updates verlieren! Wie in den Kommentaren von Eliseu Monar erwähnt, sollten Sie veränderbare Objekte klonen, bevor Sie sie mutieren. React hat Unveränderlichkeitshelfer , die helfen können.

Eine andere Möglichkeit besteht darin, darauf zu verzichten, veränderbare Datenstrukturen überhaupt direkt im Zustand zu halten. Das oben erwähnte Flussmuster ist eine interessante Interpretation dieser Idee.


Auf der React-Website gibt es einen großartigen Artikel mit dem Titel " Thinking in React", in dem erläutert wird , wie Sie eine Idee oder ein Modell in eine React-Anwendung umwandeln können. Ich empfehle dringend, darüber nachzudenken. Schauen wir uns als konkretes Beispiel den von Ihnen bereitgestellten Code an. Sie müssen im Wesentlichen ein Datenelement verwalten: eine Liste der Inhalte, die im containerElement vorhanden sind. Alle Änderungen an Ihrer Benutzeroberfläche können durch Hinzufügen, Entfernen und Ändern dieser Daten dargestellt werden.

Wenn Sie die oben genannten Grundsätze anwenden, sieht Ihre endgültige Bewerbung möglicherweise folgendermaßen aus:

/** @jsx React.DOM */

var Application = React.createClass({
  getInitialState: function() {
    return {
      content: []
    };
  },

  render: function() {
    return (
      <div className="container">
        <span className="header">jQuery to React.js Header</span>
        <button className="add_button"
                onClick={this.addContent}>Add Element</button>
        <button className="add_button"
                onClick={this.timedAddContent}>Add Element in 3 Seconds</button>
        {this.state.content.map(function(content) {
          return <ContentItem content={content} removeItem={this.removeItem} />;
        }.bind(this))}
      </div>
    );
  },

  addContent: function() {
    var newItem = {className: "added_content", text: "Click to close"},
        content = this.state.content,
        newContent = React.addons.update(content, {$push: [newItem]});
    this.setState({content: newContent});
  },

  timedAddContent: function() {
    setTimeout(function() {
      var newItem = {className: "timed_added_content", text: "Click to close"},
          content = this.state.content,
          newContent = React.addons.update(content, {$push: [newItem]});
      this.setState({content: newContent});
    }.bind(this), 3000);
  },

  removeItem: function(item) {
    var content = this.state.content,
        index = content.indexOf(item);
    if (index > -1) {
      var newContent = React.addons.update(content, {$splice: [[index, 1]]});
      this.setState({content: newContent});
    }
  }
});

var ContentItem = React.createClass({
  propTypes: {
    content: React.PropTypes.object.isRequired,
    removeItem: React.PropTypes.func.isRequired
  },

  render: function() {
    return <span className={this.props.content.className}
                 onClick={this.onRemove}>{this.props.content.text}</span>;
  },

  onRemove: function() {
    this.props.removeItem(this.props.content);
  }
});

React.renderComponent(<Application />, document.body);

Sie können den Code in Aktion in dieser JSFiddle sehen : http://jsfiddle.net/BinaryMuse/D59yP/

Die Anwendung besteht aus zwei Komponenten: einer Komponente der obersten Ebene mit dem Namen Application, die (in ihrem Status) ein aufgerufenes Array verwaltet content, und einer Komponente mit dem Namen ContentItem, die die Benutzeroberfläche und das Verhalten eines einzelnen Elements aus diesem Array darstellt. ApplicationDie renderMethode von 'gibt ein ContentItemElement für jedes Element im Inhaltsarray zurück.

Zu beachten ist, dass die gesamte Logik zum Verwalten der Werte innerhalb des contentArrays in der ApplicationKomponente behandelt wird. Den ContentItemKomponenten wird ein Verweis auf Applicationdie removeItemMethode übergeben, an die die ContentItemDelegierten beim Klicken delegieren. Dadurch bleibt die gesamte Logik zum Manipulieren des Status innerhalb der Komponente der obersten Ebene erhalten.

Michelle Tilley
quelle
Großartiger Text, Brandon! Ein Rat, den ich geben möchte, ist, die Requisiten oder Statusvariablen der Komponente immer zu klonen, bevor Sie sie mutieren, wie Sie es bei der Methode "removeItem" getan haben. Ich hatte bereits Probleme damit, als eine untergeordnete Komponente dieselbe Variable verwendete. Es gibt ein Add-On, das bei der Unveränderlichkeit helfen kann: facebook.github.io/react/docs/update.html
Eliseu Monar dos Santos
Brandon, ich habe mich über die Beziehung zwischen den staatlichen Helfern und der Verwendung eines Datenspeicherobjekts innerhalb des Flussrahmens gewundert. Ich neige dazu, nur die Komponente der obersten Ebene den Laden abhören zu lassen und ihren eigenen Status festzulegen, der sich über Requisiten an die Kinder weitergibt. Ich kümmere mich nicht um die Mutationshelfer oder gar um das Kopieren der Daten, da Reaktionskomponenten die Speicher über Nachrichten aktualisieren, anstatt die Requisitenwerte zu berühren. Irgendein Rat?
Justingordon
@justingordon Ich bin mir nicht 100% sicher, ob ich Ihre Frage richtig verstehe, aber ich denke, wir sind auf derselben Seite. Ich weiß, dass SO-Kommentare ein schwieriger Ort für Diskussionen sind. Nehmen Sie Kontakt mit mir auf .
Michelle Tilley
1
Dies ist eine großartige Zusammenfassung, danke! Ich bereite mich darauf vor, React für andere Teams in meinem Unternehmen einzuführen, und sammle Ressourcen, von denen meine Mitarbeiter lernen und auf die sie sich beziehen können. Dies wird definitiv ganz oben auf meiner Liste stehen.
Peterjmag
2
@ Peterjmag Danke! Sie könnten auch an diesem Repo interessiert sein, das ich gemacht habe, sowie an diesem Video, das ich von einem Workshop gemacht habe, den ich bei der Arbeit gegeben habe (passt zu diesem Repo )
Michelle Tilley