React: Adereços padrão na sintaxe de classe ES6

Criado em 22 abr. 2015  ·  40Comentários  ·  Fonte: facebook/react

O anúncio de suporte ES6 diz:

a maneira idiomática de especificar o estado da classe é apenas usar uma propriedade de instância simples. Da mesma forma, getDefaultProps e propTypes são, na verdade, apenas propriedades no construtor.

Isso faz muito sentido para mim, mas percebi algumas pequenas inconsistências que podem valer a pena repensar.

Ao usar a sintaxe .createClass , o valor retornado por getDefaultProps parece ser usado em outros pontos do ciclo de vida do componente - não apenas no construtor. Por exemplo, se eu inspecionar o que é enviado para componentWillReceiveProps(props) , posso ver que os adereços padrão são aplicados.

Isso _não_ parece ser o caso ao usar a sintaxe de classe ES6, o que significa que tenho que duplicar o código. Aqui está um exemplo do que quero dizer:

class Control extends React.Component {

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

  // ...

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

}

Como você pode ver, estou duplicando a expressão props.value = props.value || '' . Se eu tivesse mais de um padrão, obviamente teria muito mais duplicação.

Ao usar o método .createClass , eu poderia retornar {value: ''} do método getDefaultProps , e isso funcionaria, e eu teria que fazer isso apenas uma vez.

Faz sentido restaurar esse método para evitar duplicação desnecessária? Existe outra abordagem mais semelhante ao React que eu não conheço?

Comentários muito úteis

Está correto. Em vez disso, você escreve isto:

class Control extends React.Component {

  // ...

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

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

Isso funciona para você?

Todos 40 comentários

Os adereços padrão já devem estar mesclados quando componentWillReceiveProps é chamado.

Os adereços padrão já devem estar mesclados quando componentWillReceiveProps é chamado.

Pelo que eu posso dizer, getDefaultProps nunca é chamado ao usar a sintaxe da classe ES6.

Está correto. Em vez disso, você escreve isto:

class Control extends React.Component {

  // ...

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

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

Isso funciona para você?

Ahh, desculpe, vejo isso na documentação agora. Obrigado!

Como cheguei aqui a partir de uma pesquisa do Google e prefiro class para encapsular meu código, os adereços padrão podem ser definidos usando propriedades computadas como:

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

@jhabdas O que você forneceu não é uma sintaxe ES2015, eu acho; Babel lança token inesperado se eu usar os adereços estáticos, no entanto, para aqueles caras que trabalham como eu no es2015, aqui está um material de trabalho.

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

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

}

atualizar

Depois de instalar o link de @zpao , posso usar propriedades estáticas ...

@ Gopikrishna19 você precisaria habilitar outro plugin babel que implementa as propriedades da classe proprosal: http://babeljs.io/docs/plugins/transform-class-properties/

@zpao Ooh! Outra coisa nova hoje :) vou tentar isso, muito obrigado!

@ Gopikrishna19 Na verdade, gosto do trecho de código que você postou b / c, posso fazer um pré-processamento antes de inicializar os adereços padrão. Obrigado por mencionar isso.

Isso parece estar funcionando e é mais elegante na minha opinião:

....

 static defaultProps = {
      //someDefaultProps
  };

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

....

@fxhereng O segundo argumento é reservado para context portanto, evito substituí-lo por algum significado personalizado, pois isso pode falhar em versões futuras.

Ok @gaearon. Qual é a melhor maneira de definir adereços padrão para você?

Obrigado,

Qual é a forma recomendada para fazer isso?

Se você usar a transformação experimental http://babeljs.io/docs/plugins/transform-class-properties/ , então você pode apenas usar static defaultProps = {...}; . Não há necessidade de alterações no construtor. Caso contrário, você precisa atribuir fora:

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

Também..

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

@efernandesng Este não é um padrão compatível. Ele não se comportará como defaultProps e sofrerá uma mutação em this.props que você não deve fazer.

Parece que não consigo instanciar defaultProps com a classe pai para que eu possa passar esses adereços para outra classe filha dentro.

Existe uma maneira es6 padrão de fazer isso? Todos os métodos aqui não funcionam para mim.

Parece que não consigo instanciar defaultProps com a classe pai para que eu possa passar esses adereços para outra classe filha dentro.

Eu não entendo o que você quer dizer. você pode mostrar um exemplo?

Claro, sinto muito por isso.

Aqui está um componente:

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;

Quando executo o webpack-dev-server, recebo este erro:
Uncaught ReferenceError: props is not defined

Deve haver algo que eu fiz de errado ...

props é uma variável não associada em seu método render() . Deve ser <TimerView {...this.props} /> .

Oh meu.
Eu perdi totalmente este. Acho que, como estou usando componentes sem estado tanto quanto classes, fiquei confuso com isso.

Obrigado senhor.

sem problemas @jeanmichelcote! acontece :)

Acessar outros adereços para definir defaultProps é considerado um antipadrão?

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 parece que você está tentando fazer referência a uma variável de instância de um método estático. Você não pode fazer isso porque não há como saber de qual this você está falando. Por definição, coisas estáticas sempre vivem fora do contexto de uma instância.

@romulof Isso é comum com todas as linguagens orientadas a objetos. A sintaxe da seta grande se vincula ao contexto em que é definida. Talvez você possa tentar usar

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

@sbussard : Exatamente.

Minha pergunta é sobre defaultProps sendo implementado como um objeto estático.
Talvez permitindo que seja uma função, para ser chamada pelo construtor.

Ele está intencionalmente fora da classe para que um compilador otimizador possa embuti-lo no site da chamada.

Então, qual é a resposta final?

@gaearon você mencionou isso

Ele está intencionalmente fora da classe para que um compilador otimizador possa embuti-lo no site da chamada.

mas isso significa que não pode ser otimizado ao usar "campos de instância de classe" e / ou "campos estáticos de classe"? Acho que estou tentando entender qual abordagem é a preferida e por quê.

Então, qual é a resposta final?

Se você quiser manter o ES6, atribua-o na parte inferior:

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

Se estiver usando Create React App ou se estiver confortável com a sintaxe experimental e tiver habilitado a transformação das propriedades de classe , você pode fazer isso:

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

Essas abordagens são completamente equivalentes. Observe que se você também estiver usando decoradores, pode haver bugs estranhos combinando essas transformações. Portanto, não recomendo usar decoradores junto com propriedades de classe.

Eu espero que isso ajude!

mas isso significa que não pode ser otimizado ao usar "campos de instância de classe" e / ou "campos estáticos de classe"? Acho que estou tentando entender qual abordagem é a preferida e por quê.

Não há diferença entre atribuir no final e usar propriedades de classe. Propriedades de classe são desugar para atribuição. Use o REPL no site do Babel para verificar para qual código compila.

Estou curioso sobre o mesmo assunto sobre o qual @romulof fala. Claro, posso usar static defaultProps para definir propriedades padrão, mas e se eu quiser usar o contexto?

Por que isso é útil?

Eu tenho um componente modal genérico que tem title e onSubmit props. Às vezes, quero usar o Modal com os mesmos adereços, mas de partes completamente diferentes do meu aplicativo. Para title isso funciona muito bem.

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

No entanto, o manipulador onSubmit , que por acaso é um pedaço de código decente, requer contexto porque ele usa um prop preenchido pelo redux de conexão. Atualmente não há como abstrair esse código porque o contexto não pode ser usado para definir os adereços da classe pai.

O que estou tentando fazer não é realmente um antipadrão (ou pelo menos acho que não é), então me pergunto se há outra maneira de fazer isso?

Eu esperava ser capaz de fazer algo como

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

mas não funciona.

@roberttod você encontrou uma solução para o seu problema? Obrigado

Eu quero fazer uma pergunta complementar,
se estou usando o app create react (react-scripts v1.0.12), posso definir os estados iniciais como

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  state = {...};
}

qual é a diferença em comparação com o uso de construtores para definir estados iniciais como:

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  constructor(props) {
    super(props);

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

especificamente, há alguma implicação de desempenho na primeira abordagem?

É exatamente a mesma coisa, não há diferença.

@jhabdas Bem, então quando o defaultProps é definido como:

static defaultProps = {
}

Como acessá-lo a partir dos métodos de classe desde:

this.defaultProps

retorna undefined

@majioa Não sei sobre essa API de nível de classe, mas uma ideia é armazenar em cache os adereços padrão como um objeto separado e fazer referência a isso. O que você acha?

@majioa

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

Eu encontro o mesmo problema, você deve instalar o babel-plugin-transform-class-properties

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

em seguida, adicione "transform-class-properties" a .babelrc

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

static get defaultProps () {
Retorna {
carro: "Mercedes"
}

@ Arm7107 Isso é ineficiente porque cria um novo objeto sempre que um elemento é criado. Eu recomendo fortemente não usar isso. Atribua uma propriedade:

MyComponent.defaultProps = {
  // ...
}

ou use a sintaxe experimental de propriedades de classe estática:

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

  // ...
}

(para o qual você precisará de um plugin Babel)

Bloquearei esse problema para evitar que outras sugestões incorretas apareçam nos resultados do Google.

Esta página foi útil?
0 / 5 - 0 avaliações