Status oder Refs in React.js Formularkomponenten verwenden?

116

Ich beginne mit React.js und möchte ein einfaches Formular erstellen, aber in der Dokumentation habe ich zwei Möglichkeiten gefunden, dies zu tun.

Der erste verwendet Refs :

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Und der zweite verwendet den Status innerhalb der React-Komponente:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

Ich kann die Vor- und Nachteile der beiden Alternativen nicht erkennen, wenn es welche gibt. Vielen Dank.

gabrielgiussi
quelle
Vermisse ich hier etwas? Warum verwenden Sie das Ereignisobjekt nicht, um die Formularwerte abzurufen? Dies scheint der einzige Grund zu sein, hier überhaupt ein Formular zu verwenden. Wenn Sie nicht das Standardübermittlungsverhalten verwenden und Verweise auf die Eingaben haben, müssen Sie diese nicht in ein Formular einschließen.
NectarSoft

Antworten:

143

Die Kurzversion: Vermeiden Sie Refs.


Sie sind schlecht für die Wartbarkeit und verlieren viel von der Einfachheit des WYSIWYG-Modell-Renderings.

Du hast ein Formular. Sie müssen eine Schaltfläche hinzufügen, die das Formular zurücksetzt.

  • refs:
    • manipuliere das DOM
    • Rendern beschreibt, wie das Formular vor 3 Minuten aussah
  • Zustand
    • setState
    • Rendern beschreibt, wie das Formular aussieht

Sie haben ein CCV-Nummernfeld in einer Eingabe und einige andere Felder in Ihrer Anwendung, die Zahlen sind. Jetzt müssen Sie erzwingen, dass der Benutzer nur noch Zahlen eingibt.

  • refs:
    • Fügen Sie einen onChange-Handler hinzu (verwenden wir nicht refs, um dies zu vermeiden?)
    • manipuliere dom in onChange, wenn es keine Zahl ist
  • Zustand
    • Sie haben bereits einen onChange-Handler
    • Fügen Sie eine if-Anweisung hinzu, wenn sie ungültig ist, tun Sie nichts
    • Rendern wird nur aufgerufen, wenn ein anderes Ergebnis erzielt wird

Eh, egal, der PM möchte, dass wir nur einen roten Kastenschatten machen, wenn er ungültig ist.

  • refs:
    • Lassen Sie den onChange-Handler einfach forceUpdate aufrufen oder so?
    • Renderausgabe basierend auf ... huh?
    • Woher bekommen wir den Wert, der beim Rendern validiert werden soll?
    • die className dom-Eigenschaft eines Elements manuell bearbeiten?
    • ich bin verloren
    • ohne refs umschreiben?
    • Aus dem Dom in Render lesen, wenn wir gemountet sind, sonst gültig annehmen?
  • Zustand:
    • Entfernen Sie die if-Anweisung
    • Machen Sie das Rendern basierend auf this.state validieren

Wir müssen dem Elternteil die Kontrolle zurückgeben. Die Daten sind jetzt in Requisiten und wir müssen auf Änderungen reagieren.

  • refs:
    • Implementieren Sie componentDidMount, componentWillUpdate und componentDidUpdate
    • manuell die vorherigen Requisiten unterscheiden
    • Manipulieren Sie den Dom mit minimalen Änderungen
    • Hallo! Wir implementieren Reagieren in Reagieren ...
    • Es gibt noch mehr, aber meine Finger tun weh
  • Zustand:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

Die Leute denken, Schiedsrichter sind "einfacher", als sie im Zustand zu halten. Dies mag für die ersten 20 Minuten zutreffen, nach meiner Erfahrung danach jedoch nicht mehr. Versetzen Sie sich in die Lage zu sagen "Ja, ich werde es in 5 Minuten erledigen lassen" anstatt "Sicher, ich werde nur ein paar Komponenten neu schreiben".

Räuber
quelle
3
Könnten Sie etwas mehr über sed -es / this.state / this.props / 's / handleChange / onChange /' -i form.js erklären?
gabrielgiussi
1
Nein, ich meine tatsächliche Änderungen am Dom. React.findDOMNode(this.refs.foo). Wenn Sie zB ändern this.refs.foo.props.bar, passiert nichts.
Brigand
1
Beispiel: Wenn Sie es <input onChange={this.handleChange} value={this.state.foo} />geändert haben <input onChange={this.props.handleChange} value={this.props.foo} />oder Ihre handleChange-Funktion (en) ändern, um die Rückrufe in Requisiten aufzurufen. In jedem Fall sind es ein paar kleine offensichtliche Änderungen.
Brigand
4
Ich bin mir nicht sicher, ob ich der einzige bin, der Ihre Antwort etwas verwirrend findet. Könnten Sie einige Codebeispiele zeigen, um Ihre Punkte klarer zu machen?
Rishabh
2
Es ist unerwünscht, mehr als 50 Eingaben auf einem Bildschirm zu haben und bei jeder Zustandsänderung jeweils zu rendern. inputIdeal ist es, jedes Feld zu komponieren , in dem jedes seinen eigenen Status beibehält. Irgendwann müssen wir diese verschiedenen unabhängigen Zustände mit einem größeren Modell in Einklang bringen. Vielleicht haben wir eine automatische Speicherung für einen Timer, oder wir sparen nur bei componentWillUnmountHier finde ich es refsideal, während der Abstimmung pflücken wir den stateWert von jedem ref, und keiner ist klüger. Ich stimme in den meisten Fällen stateder Antwort zu, aber bei einer großen Anzahl von inputsist die Verwendung eines geeigneten refsMusters ein Segen für die Leistung
Lux
105

Ich habe einige Leute gesehen, die die obige Antwort als Grund angeführt haben, "niemals Refs zu verwenden", und ich möchte meine Meinung (sowie einige andere React-Entwickler, mit denen ich gesprochen habe) abgeben.

Die Einstellung "Refs nicht verwenden" ist korrekt, wenn davon gesprochen wird, sie für Komponenteninstanzen zu verwenden. Das heißt, Sie sollten refs nicht verwenden, um Komponenteninstanzen abzurufen und Methoden für sie aufzurufen. Dies ist die falsche Art, Refs zu verwenden, und wenn Refs schnell nach Süden gehen.

Die richtige (und sehr nützliche) Art, Refs zu verwenden, besteht darin, sie zu verwenden, um einen Wert aus dem DOM zu erhalten. Wenn Sie beispielsweise ein Eingabefeld haben, das einen Ref an diesen Eingang anfügt, ist es in Ordnung, den Wert später über den Ref abzurufen. Ohne diese Methode müssen Sie einen ziemlich koordinierten Prozess durchlaufen, um Ihr Eingabefeld entweder mit Ihrem lokalen Bundesstaat oder Ihrem Flussmittelspeicher auf dem neuesten Stand zu halten - was unnötig erscheint.

2019 edit: Hallo Freunde der Zukunft. Zusätzlich zu dem, was ich vor einigen Jahren erwähnt habe, sind Refs mit React Hooks auch eine großartige Möglichkeit, Daten zwischen Renderings zu verfolgen, und beschränken sich nicht nur darauf, DOM-Knoten zu greifen.

Tyler McGinnis
quelle
3
Ihr letzter Absatz ist absolut sinnvoll, aber können Sie Ihren zweiten Absatz klarstellen? Was ist ein konkretes Beispiel für das Abrufen einer Komponenteninstanz und das Aufrufen einer Methode, die als falsch angesehen wird?
Danny Libin
2
Ich würde dem zustimmen. Ich verwende Refs, es sei denn / bis ich den Wert eines Feldes validieren oder manipulieren muss. Wenn ich Änderungen ändern oder Werte programmgesteuert ändern muss, verwende ich state.
Christopher Davies
1
Dem stimme ich auch zu. Während einer Entdeckungsphase habe ich mich absichtlich einem Bildschirm mit einer großen Anzahl von Eingaben mit Naivität genähert. Alle Eingabewerte, die in einer Karte (im Status) gespeichert sind und mit der ID versehen sind. Es ist unnötig zu erwähnen, dass die Leistung seit dem Festlegen des Status und dem Rendern von mehr als 50 Eingaben (einige Material-UI, die schwer waren!) Bei so geringfügigen Änderungen an der Benutzeroberfläche wie einem Kontrollkästchen-Klick nicht ideal war. Es schien der richtige Ansatz zu sein, jeden Eingang zu komponieren, der seinen eigenen Zustand beibehalten kann. Wenn eine Abstimmung erforderlich ist, schauen Sie einfach in die refsund erhalten Sie den Statuswert. Es scheint tatsächlich ein wirklich schönes Muster zu sein.
Lux
2
Ich stimme vollkommen zu. Die akzeptierte Antwort ist meiner Meinung nach zu vage.
James Wright
Genau. Beim Entwerfen einer allgemeinen Formularkomponente werden die Schwachstellen kontrollierter Komponenten und das Verwalten von Fokus, Fehlerbehandlung usw. ans Licht gebracht. Eine saubere Architektur ist tatsächlich nicht möglich. Sprechen Sie bei Bedarf mit mir. Ich verschiebe meine Komponenten zu Refs.
Kushalvm
6

TL; DR Im Allgemeinen verstoßen refsSie gegen die deklarative Philosophie von React , daher sollten Sie sie als letzten Ausweg verwenden. Verwenden Sie state / propswann immer möglich.


Um zu verstehen, wo Sie refsvs verwenden state / props, schauen wir uns einige der Designprinzipien an, denen React folgt.

Per React Dokumentation überrefs

Vermeiden Sie die Verwendung von Refs für alles, was deklarativ erfolgen kann.

Per Reacts Designprinzipien für Fluchtluken

Wenn es schwierig ist, ein Muster, das zum Erstellen von Apps nützlich ist, deklarativ auszudrücken, stellen wir eine zwingende API dafür bereit. (und sie verlinken hier auf Refs)

Das heißt, das Team von React schlägt vor, dies zu vermeiden refsund zu verwendenstate / props alles , was auf reaktive / deklarative Weise getan werden kann.

@ Tyler McGinnis hat eine sehr gute Antwort gegeben , die auch besagt

Die richtige (und sehr nützliche) Art, Refs zu verwenden, besteht darin, sie zu verwenden, um einen Wert aus dem DOM zu erhalten ...

Während Sie das tun können, arbeiten Sie gegen die Philosophie von React. Wenn Sie einen Wert in einer Eingabe haben, kommt dieser mit Sicherheit von state / props. Um den Code konsistent und vorhersehbar zu halten, sollten Sie sich auch daran halten state / props. Ich erkenne die Tatsache an, dass Sie refsmanchmal die schnellere Lösung erhalten. Wenn Sie also einen Proof of Concept durchführen, schnell und schmutzig akzeptabel.

Dies lässt uns einige konkrete Anwendungsfälle fürrefs

Verwalten des Fokus, der Textauswahl oder der Medienwiedergabe. Imperative Animationen auslösen. Integration in DOM-Bibliotheken von Drittanbietern.

Lyubomir
quelle
5

Dieser Beitrag ist alt.

Ich werde meine kleinen Erfahrungen in einem Fall in dieser Angelegenheit teilen.

Ich habe an einer großen Komponente (414 Zeilen) mit vielen 'dynamischen' Eingaben und vielen zwischengespeicherten Daten gearbeitet. (Ich arbeite nicht alleine an der Seite und meine Sinne sagen mir, dass die Struktur des Codes wahrscheinlich besser aufgeteilt werden könnte, aber es ist nicht der Punkt (nun, es könnte sein, aber ich beschäftige mich damit)

Ich habe zuerst mit state gearbeitet, um die Werte der Eingaben zu verarbeiten:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

und natürlich in den Eingaben:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

Das Rendern war so umfangreich, dass die Eingabeänderung abgehackt war wie **** (versuchen Sie nicht, die Taste gedrückt zu halten, Text wird erst nach einer Pause angezeigt)

Ich war mir sicher, dass ich dies mit Refs vermeiden könnte.

endete so:

  const inputsRef = useRef([])

und in den Eingängen:

ref={input => (inputsRef.current[id] = input)}

[Nun, in meinem Fall war die Eingabe Material-UI TextField, also:

inputRef={input => (inputsRef.current[id] = input)}

]]

Dank dessen gibt es kein erneutes Rendern, die Eingabe ist reibungslos, funktioniert genauso. Das spart Zyklen und Berechnungen, also auch Energie. Mach es für die Erde x)

Mein Fazit: useRef für Eingabewerte kann sogar benötigt werden.

Kaphar
quelle