React: Standard-Requisiten in der ES6-Klassensyntax

Erstellt am 22. Apr. 2015  ·  40Kommentare  ·  Quelle: facebook/react

In der Ankündigung zum ES6-Support heißt es:

der idiomatische Weg, den Klassenstatus anzugeben, besteht darin, einfach eine einfache Instanzeigenschaft zu verwenden. Ebenso sind getDefaultProps und propTypes eigentlich nur Eigenschaften des Konstruktors.

Das macht für mich sehr viel Sinn, aber mir sind einige kleine Ungereimtheiten aufgefallen, die es wert sein könnten, noch einmal darüber nachgedacht zu werden.

Bei Verwendung der ursprünglichen .createClass Syntax scheint der von getDefaultProps Wert an anderen Stellen im Komponentenlebenszyklus verwendet zu werden – nicht nur im Konstruktor. Wenn ich beispielsweise überprüfe, was an componentWillReceiveProps(props) gesendet wird, kann ich sehen, dass die Standardeigenschaften angewendet werden.

Dies scheint bei der Verwendung der ES6-Klassensyntax _nicht_ der Fall zu sein, was bedeutet, dass ich Code duplizieren muss. Hier ist ein Beispiel für das, was ich meine:

class Control extends React.Component {

  constructor(props) {
    props.value = props.value || '';
    super(props);
  }

  // ...

  componentWillReceiveProps(props) {
    props.value = props.value || '';
    // Do something with props...
  }

}

Wie Sie sehen, dupliziere ich den Ausdruck props.value = props.value || '' . Wenn ich mehr als einen Standardwert hätte, hätte ich natürlich viel mehr Duplikate.

Wenn ich die Methode .createClass verwende, könnte ich {value: ''} von der Methode getDefaultProps , und dies würde funktionieren, und ich müsste es nur einmal tun.

Ist es sinnvoll, diese Methode wiederherzustellen, um unnötige Duplizierungen zu vermeiden? Gibt es einen anderen, eher React-ähnlichen Ansatz, den ich nicht kenne?

Hilfreichster Kommentar

Das ist richtig. Stattdessen schreibst du dies:

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

Funktioniert das für dich?

Alle 40 Kommentare

Beim Aufruf von componentWillReceiveProps sollten die Standardprops bereits eingebunden sein.

Beim Aufruf von componentWillReceiveProps sollten die Standardprops bereits eingebunden sein.

Soweit ich das beurteilen kann, wird getDefaultProps bei Verwendung der ES6-Klassensyntax nie aufgerufen.

Das ist richtig. Stattdessen schreibst du dies:

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

Funktioniert das für dich?

Ahh, sorry, das sehe ich jetzt in der Dokumentation. Vielen Dank!

Da ich über eine Google-Suche hier gelandet bin und ich das class bevorzuge, um meinen Code zu kapseln, können die Standardprops mit berechneten Eigenschaften wie folgt festgelegt werden:

import React, {Component, PropTypes} from 'react'
class DefaultPropsExample extends Component {
  static defaultProps = {
    ...Component.defaultProps,
    instructions: 'Usage instructions not provided.',
  }
}

@jhabdas Was Sie angegeben haben, ist keine ES2015-Syntax, denke ich; Babel wirft unerwartete Zeichen, wenn ich die statischen Requisiten verwende, aber für diejenigen, die wie ich in es2015 arbeiten, hier ist ein funktionierendes Zeug.

import React from 'react';
export default class extends React.Component {

  static get defaultProps() {
    return {
      // stuff you want :)
    }
  }

}

aktualisieren

Nach der Installation des Links von

@Gopikrishna19 Sie müssten ein anderes Babel-Plugin aktivieren, das den Vorschlag der Klasseneigenschaften implementiert: http://babeljs.io/docs/plugins/transform-class-properties/

@zpao Ooh! Heute wieder was Neues :) werde das mal ausprobieren, vielen Dank!

@Gopikrishna19 Ich mag das Code-Snippet, das Sie gepostet haben, tatsächlich. Ich kann einige Vorverarbeitungen durchführen, bevor Sie die Standard-Requisiten initialisieren. Danke für die Erwähnung.

Das scheint zu funktionieren und ist meiner Meinung nach eleganter:

....

 static defaultProps = {
      //someDefaultProps
  };

  constructor(props, defaultProps) {
    super(props, defaultProps);
  }

....

@fxhereng Das zweite Argument ist für context reserviert, daher würde ich es vermeiden, es mit einer benutzerdefinierten Bedeutung zu überschreiben, da dies in zukünftigen Versionen möglicherweise nicht mehr funktioniert.

Ok @gaearon Was ist der beste Weg, um Standard-Requisiten für Sie

Vielen Dank,

Was ist der empfohlene Weg dazu?

Wenn Sie die experimentelle Transformation http://babeljs.io/docs/plugins/transform-class-properties/ verwenden , können Sie einfach static defaultProps = {...}; . Keine Änderungen am Konstruktor erforderlich. Andernfalls müssen Sie außerhalb zuweisen:

class X extends React.Component {
}
X.defaultProps = {...};

Ebenfalls..

class X extends React.Component {
  props = {
    ...
  }
}

@efernandesng Dies ist kein unterstütztes Muster. Es verhält sich nicht wie defaultProps und mutiert this.props was Sie nicht tun sollten.

Scheint, als ob ich defaultProps nicht mit der Elternklasse instanziieren kann, damit ich diese Requisiten an eine andere untergeordnete Klasse weitergeben kann.

Gibt es dafür eine Standardmethode von es6? Alle Methoden hier funktionieren bei mir nicht.

Scheint, als ob ich defaultProps nicht mit der Elternklasse instanziieren kann, damit ich diese Requisiten an eine andere untergeordnete Klasse weitergeben kann.

Ich verstehe nicht, was du meinst. Können Sie ein Beispiel zeigen?

Das tut mir natürlich leid.

Hier eine Komponente:

import React, 
{
  Component,
  PropTypes
}                     from 'react';
import { TimerView }  from './TimerView'

class Timer extends Component {
  constructor(props) {
    super(props);
  }

  componentWillReceiveProps(props) {
    console.log('Will receive props')
  }

  render() {
    console.log("Timer loaded")

    return (
      <TimerView {...props} />
    )
  }
}

Timer.propTypes = {
  status: PropTypes.string.isRequired,
};

Timer.defaultProps = {
  status: "This is the Timer",
};

export default Timer;

Wenn ich den webpack-dev-server ausführe, erhalte ich diese Fehlermeldung:
Uncaught ReferenceError: props is not defined

Irgendwas muss ich falsch machen...

props ist eine ungebundene Variable in Ihrer Methode render() . Es sollte <TimerView {...this.props} /> .

Oh mein.
Diese habe ich total vermisst. Ich denke, da ich zustandslose Komponenten genauso wie Klassen verwende, war ich bei dieser nur verwirrt.

Danke mein Herr.

kein problem @jeanmichelcote! es passiert :)

Wird der Zugriff auf andere Requisiten zum Definieren von defaultProps als Anti-Pattern angesehen?

class Comp extends from React.Component {
  static propTypes: {
    num: React.PropTypes.number.isRequired,
    action: React.PropTypes.func,
  };

  static defaultProps: {
    action: () => console.log(this.props.num), // "this" is invalid in static context
  };

  render() {
    return (
      <button onClick={this.props.action}>
        {`Log #${this.props.num}`}
      </button>
    );
  }
}

@romulof es sieht so aus, als ob Sie versuchen, von einer statischen Methode auf eine Instanzvariable zu verweisen. Sie können das nicht tun, weil Sie nicht sagen können, von welchem this Sie sprechen. Statische Dinge leben per Definition immer außerhalb des Kontexts einer Instanz.

@romulof Das ist bei allen objektorientierten Sprachen üblich. Die Fettpfeil-Syntax bindet sich an den Kontext, in dem sie definiert ist. Vielleicht könnten Sie es mit versuchen

static defaultProps: {
    action: function() {
        console.log(this.props.num), // "this" depends on the context where it is run
    }
};

@sbussard : Genau.

Meine Frage defaultProps die Implementierung von
Vielleicht darf es eine Funktion sein, die vom Konstruktor aufgerufen wird.

Es befindet sich absichtlich außerhalb der Klasse, damit ein optimierender Compiler es an der Aufrufstelle inline einbinden kann.

Was ist also die endgültige Antwort?

@gaearon das hast du schon erwähnt

Es befindet sich absichtlich außerhalb der Klasse, damit ein optimierender Compiler es an der Aufrufstelle inline einbinden kann.

aber bedeutet das, dass es nicht optimiert werden kann, wenn "Klasseninstanzfelder" und / oder "statische Klassenfelder" verwendet werden? Ich denke, ich versuche zu verstehen, welcher Ansatz bevorzugt wird und warum.

Was ist also die endgültige Antwort?

Wenn Sie bei ES6 bleiben möchten, weisen Sie es unten zu:

class MyComponent extends Component { /* ... */ }
MyComponent.defaultProps = { /* ... */ };

Wenn Sie Create React App verwenden oder mit experimenteller Syntax vertraut sind und die Klasseneigenschaftentransformation aktiviert haben, können Sie Folgendes tun:

class MyComponent extends Component {
  static defaultProps = { /* ... */ };
  /* ... */
}

Diese Ansätze sind völlig gleichwertig. Beachten Sie, dass bei der Verwendung von Dekoratoren möglicherweise seltsame Fehler auftreten, die diese Transformationen kombinieren. Daher empfehle ich nicht, Decorators zusammen mit Klasseneigenschaften zu verwenden.

Ich hoffe das hilft!

aber bedeutet das, dass es nicht optimiert werden kann, wenn "Klasseninstanzfelder" und / oder "statische Klassenfelder" verwendet werden? Ich denke, ich versuche zu verstehen, welcher Ansatz bevorzugt wird und warum.

Es gibt keinen Unterschied zwischen der Zuweisung am Ende und der Verwendung von Klasseneigenschaften. Klasseneigenschaften deszuckers zur Zuweisung. Bitte verwenden Sie REPL auf der Babel-Website, um zu überprüfen, zu welchem ​​Code kompiliert wird.

Ich bin neugierig auf das gleiche Problem, über das @romulof spricht. Sicher, ich kann static defaultProps , um Standardeigenschaften zu definieren, aber was ist, wenn ich den Kontext verwenden möchte?

Warum ist das nützlich?

Ich habe eine generische modale Komponente mit title und onSubmit Requisiten. Manchmal möchte ich das Modal mit den gleichen Requisiten verwenden, aber aus völlig unterschiedlichen Teilen meiner App. Für title funktioniert das ganz gut.

class CreateUserModal extends Modal {
  static defaultProps = { title: 'Create a new user' }
}

Der onSubmit Handler, der zufällig ein anständiger Codeblock ist, erfordert jedoch Kontext, da er ein Prop verwendet, das aus der Verbindung von Redux aufgefüllt wird. Derzeit gibt es für mich keine Möglichkeit, diesen Code zu abstrahieren, da der Kontext nicht verwendet werden kann, um die Requisiten der übergeordneten Klasse festzulegen.

Was ich zu tun versuche, ist nicht wirklich ein Anti-Muster (oder zumindest denke ich, dass es das nicht ist), also frage ich mich, ob es eine andere Möglichkeit gibt, dies zu tun?

Ich hatte gehofft, ich könnte so etwas tun

class CreateUserModal extends Modal {
  constructor (props) {
    super({
      title: 'Create a new user',
      onSubmit: () => {
        // do a load of stuff using props
      }
    })
  }
}

aber es funktioniert nicht.

@roberttod hast du eine lösung für dein problem gefunden? Vielen Dank

Ich möchte eine Folgefrage stellen,
Wenn ich die Create-Reaktion-App (react-scripts v1.0.12) verwende, ist es in Ordnung, Anfangszustände als zu definieren?

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  state = {...};
}

Was ist der Unterschied zur Verwendung von Konstruktoren, um Anfangszustände wie folgt zu definieren:

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  constructor(props) {
    super(props);

    this.state = {...};
  }
}

Hat der erste Ansatz insbesondere Auswirkungen auf die Leistung?

Es ist genau dasselbe, es gibt keinen Unterschied.

@jhabdas Nun, wenn also defaultProps definiert ist als:

static defaultProps = {
}

So greifen Sie über die Klassenmethoden darauf zu, seit:

this.defaultProps

gibt undefined

@majioa Ich kenne diese API auf Klassenebene nicht, aber eine Idee besteht darin, die Standardprops als separates Objekt zwischenzuspeichern und darauf zu verweisen. Was denken Sie?

@majioa

class Foo extends React.Component {
  static defaultProps = { param: 1 };
  render() {
    return Foo.defaultProps.param;
  }
}

Ich habe das gleiche Problem, du solltest babel-plugin-transform-class-properties installieren ,

npm install -D babel-plugin-transform-class-properties

dann füge "transform-class-properties" zu .babelrc . hinzu

{
  "presets": ["env", "react"],
  "plugins": ["react-hot-loader/babel", "transform-class-properties"]
}

statisch get defaultProps() {
Rückkehr {
Auto: "Mercedes"
}

@Arm7107 Dies ist ineffizient, da jedes Mal, wenn ein Element erstellt wird, ein neues Objekt erstellt wird. Ich rate dringend davon ab , dies zu verwenden. Weisen Sie entweder eine Eigenschaft zu:

MyComponent.defaultProps = {
  // ...
}

oder verwenden Sie die experimentelle Syntax für statische Klasseneigenschaften:

class MyComponent extends React.Component {
  static defaultProps = {
    // ...
  };

  // ...
}

(dafür brauchst du ein Babel-Plugin)

Ich werde dieses Problem beheben, um zu verhindern, dass weitere falsche Vorschläge in den Google-Ergebnissen angezeigt werden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen