React: Accessoires par défaut dans la syntaxe de la classe ES6

Créé le 22 avr. 2015  ·  40Commentaires  ·  Source: facebook/react

L' annonce de support ES6 dit:

la manière idiomatique de spécifier l'état de la classe consiste simplement à utiliser une simple propriété d'instance. De même, getDefaultProps et propTypes ne sont en réalité que des propriétés sur le constructeur.

Cela a beaucoup de sens pour moi, mais j'ai remarqué quelques petites incohérences qui méritent peut-être d'être repensées.

Lors de l'utilisation de la syntaxe .createClass , la valeur renvoyée par getDefaultProps semble être utilisée à d'autres stades du cycle de vie du composant, pas seulement dans le constructeur. Par exemple, si j'inspecte ce qui est envoyé à componentWillReceiveProps(props) , je peux voir que les accessoires par défaut sont appliqués.

Cela _ne semble pas_ être le cas lors de l'utilisation de la syntaxe de classe ES6, ce qui signifie que je dois dupliquer le code. Voici un exemple de ce que je veux dire :

class Control extends React.Component {

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

  // ...

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

}

Comme vous pouvez le voir, je duplique l'expression props.value = props.value || '' . Si j'avais plus d'un défaut, j'aurais évidemment beaucoup plus de doublons.

En utilisant la méthode .createClass , je pourrais retourner {value: ''} partir de la méthode getDefaultProps , et cela fonctionnerait, et je n'aurais à le faire qu'une seule fois.

Est-il judicieux de restaurer cette méthode pour éviter les doublons inutiles ? Existe-t-il une autre approche, plus proche de React, dont je ne suis pas au courant ?

Commentaire le plus utile

C'est correct. Au lieu de cela, vous écrivez ceci :

class Control extends React.Component {

  // ...

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

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

Est-ce que ça marche pour toi?

Tous les 40 commentaires

Les accessoires par défaut doivent déjà être fusionnés lorsque componentWillReceiveProps est appelé.

Les accessoires par défaut doivent déjà être fusionnés lorsque componentWillReceiveProps est appelé.

Pour autant que je sache, getDefaultProps n'est jamais appelé lors de l'utilisation de la syntaxe de classe ES6.

C'est correct. Au lieu de cela, vous écrivez ceci :

class Control extends React.Component {

  // ...

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

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

Est-ce que ça marche pour toi?

Ahh, désolé, je vois ça dans la documentation maintenant. Merci!

Parce que j'ai atterri ici à partir d'une recherche Google et que je préfère le class pour encapsuler mon code, les accessoires par défaut peuvent être définis à l'aide de propriétés calculées comme ceci :

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

@jhabdas Ce que vous avez donné n'est pas une syntaxe ES2015, je suppose; Babel jette un jeton inattendu si j'utilise les accessoires statiques, cependant, pour les gars qui travaillent comme moi dans es2015, voici un truc qui fonctionne.

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

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

}

mettre à jour

Après avoir installé le lien de @zpao , je peux utiliser les propriétés statiques ...

@Gopikrishna19, vous devrez activer un autre plugin babel qui implémente la proposition de propriétés de classe : http://babeljs.io/docs/plugins/transform-class-properties/

@zpao Ooh ! Encore une nouveauté aujourd'hui :) je vais essayer ça, merci beaucoup !

@ Gopikrishna19 J'aime en fait l'extrait de code que vous avez publié

Cela semble fonctionner et c'est plus élégant à mon avis:

....

 static defaultProps = {
      //someDefaultProps
  };

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

....

@fxhereng Le deuxième argument est réservé à context j'éviterais donc de le

Ok @gaearon Quelle est la meilleure façon de définir les accessoires par défaut pour vous ?

Merci,

Quelle est la méthode recommandée pour cela ?

Si vous utilisez la transformation expérimentale http://babeljs.io/docs/plugins/transform-class-properties/ , vous pouvez simplement utiliser static defaultProps = {...}; . Pas besoin de modifier le constructeur. Sinon, vous devez affecter à l'extérieur :

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

Aussi..

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

@efernandesng Ce n'est pas un modèle pris en charge. Il ne se comportera pas comme defaultProps et il mute this.props ce que vous ne devriez pas faire.

On dirait que je ne peux pas faire en sorte que defaultProps soit instancié avec la classe parente afin que je puisse passer ces accessoires à une autre classe enfant à l'intérieur.

Existe-t-il un moyen standard es6 de le faire? Toutes les méthodes ici ne fonctionnent pas pour moi.

On dirait que je ne peux pas faire en sorte que defaultProps soit instancié avec la classe parente afin que je puisse passer ces accessoires à une autre classe enfant à l'intérieur.

Je ne comprends pas ce que tu veux dire. Pouvez-vous donner un exemple?

Bien sûr, désolé pour ça.

Voici un composant :

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;

Lorsque je lance le webpack-dev-server, j'obtiens cette erreur :
Uncaught ReferenceError: props is not defined

Il doit y avoir quelque chose que je fais mal...

props est une variable non liée dans votre méthode render() . Il devrait être <TimerView {...this.props} /> .

Oh mon.
Celui-ci m'a totalement manqué. Je suppose que puisque j'utilise des composants sans état autant que des classes, je me suis juste perdu sur celui-ci.

Merci Monsieur.

pas de problème @jeanmichelcote ! ça arrive :)

L'accès à d'autres accessoires pour définir defaultProps est-il considéré comme un anti-modèle ?

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 il semble que vous essayez de référencer une variable d'instance à partir d'une méthode statique. Vous ne pouvez pas le faire car il n'y a aucun moyen de savoir de quel this vous parlez. Par définition, les choses statiques vivent toujours en dehors du contexte d'une instance.

@romulof C'est commun à tous les langages orientés objet. La syntaxe de la grosse flèche se lie au contexte dans lequel elle est définie. Vous pourriez peut-être essayer d'utiliser

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

@sbussard : Exactement.

Ma question concerne l'implémentation de defaultProps en tant qu'objet statique.
Peut-être en lui permettant d'être une fonction, à appeler par le constructeur.

Il est intentionnellement en dehors de la classe afin qu'un compilateur d'optimisation puisse l'intégrer au site d'appel.

Alors, quelle est la réponse finale ?

@gaearon tu l'as mentionné

Il est intentionnellement en dehors de la classe afin qu'un compilateur d'optimisation puisse l'intégrer au site d'appel.

mais cela signifie-t-il qu'il ne peut pas être optimisé lors de l'utilisation de « champs d'instance de classe » et/ou de « champs statiques de classe » ? Je suppose que j'essaie de comprendre quelle approche est préférée et pourquoi.

Alors, quelle est la réponse finale ?

Si vous voulez vous en tenir à ES6, attribuez-le en bas :

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

Si vous utilisez Create React App, ou si vous êtes à l'aise avec la syntaxe expérimentale et avez activé la transformation des propriétés de classe , vous pouvez faire ceci :

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

Ces approches sont tout à fait équivalentes. Notez que si vous utilisez également des décorateurs, vous pourriez avoir des bugs étranges combinant ces transformations. Je ne recommande donc pas d'utiliser des décorateurs avec des propriétés de classe.

J'espère que ça aide!

mais cela signifie-t-il qu'il ne peut pas être optimisé lors de l'utilisation de « champs d'instance de classe » et/ou de « champs statiques de classe » ? Je suppose que j'essaie de comprendre quelle approche est préférée et pourquoi.

Il n'y a pas de différence entre l'affectation à la fin et l'utilisation des propriétés de classe. Les propriétés de la classe sont désagrégées pour l'affectation. Veuillez utiliser REPL sur le site Web de Babel pour vérifier sur quoi le code est compilé.

Je suis curieux du même problème dont @romulof parle. Bien sûr, je peux utiliser static defaultProps pour définir les propriétés par défaut, mais que se passe-t-il si je veux utiliser le contexte ?

Pourquoi est-ce utile ?

J'ai un composant modal générique qui a des accessoires title et onSubmit . Parfois, je veux utiliser le modal avec les mêmes accessoires mais à partir de parties complètement différentes de mon application. Pour title cela fonctionne très bien.

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

Cependant, le gestionnaire onSubmit , qui s'avère être un morceau de code décent, nécessite un contexte car il utilise un accessoire rempli à partir de la connexion redux. Actuellement, il n'y a aucun moyen pour moi d'abstraire ce code car le contexte ne peut pas être utilisé pour définir les accessoires de la classe parent.

Ce que j'essaie de faire n'est pas vraiment un anti-modèle (ou du moins je pense que ce n'est pas le cas) alors je me demande s'il y a une autre façon de le faire ?

J'espérais pouvoir faire quelque chose comme

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

mais ça ne marche pas.

@roberttod as -tu trouvé une solution à ton problème ? Merci

Je veux poser une question de suivi,
si j'utilise create react app (react-scripts v1.0.12), est-il correct de définir les états initiaux comme

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  state = {...};
}

quelle est la différence par rapport à l'utilisation de constructeurs pour définir les états initiaux comme :

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  constructor(props) {
    super(props);

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

en particulier, y a-t-il des implications en termes de performances dans la première approche ?

C'est exactement la même chose, il n'y a pas de différence.

@jhabdas Eh bien, donc quand le defaultProps est défini comme :

static defaultProps = {
}

Comment y accéder depuis les méthodes de classe puisque :

this.defaultProps

renvoie undefined

@majioa Je ne connais pas cette API de niveau classe, mais une idée est de mettre en cache les accessoires par défaut en tant qu'objet séparé et de s'y référer. Qu'est-ce que tu penses?

@majioa

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

Je rencontre le même problème, vous devez installer babel-plugin-transform-class-properties

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

puis ajoutez "transform-class-properties" à .babelrc

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

statique get defaultProps() {
revenir {
voiture : "Mercedes"
}

@Arm7107 Ceci est inefficace car il crée un nouvel objet chaque fois qu'un élément est créé. Je vous conseille fortement de ne pas utiliser. Soit attribuer une propriété :

MyComponent.defaultProps = {
  // ...
}

ou utilisez la syntaxe

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

  // ...
}

(pour lequel vous aurez besoin d'un plugin Babel)

Je vais verrouiller ce problème pour éviter d'autres suggestions incorrectes qui s'afficheront dans les résultats Google.

Cette page vous a été utile?
0 / 5 - 0 notes