Reaccionar: en línea condicionalmente pasar prop al componente

81

Me gustaría saber si hay una mejor manera de pasar un accesorio condicionalmente que usar una declaración if.

Por ejemplo, ahora mismo tengo:

var parent = React.createClass({
  propTypes: {
    editable: React.PropTypes.bool.isRequired,
    editableOpts: React.PropTypes.shape({...})
  },
  render: function() {
    if(this.props.editable) {
      return (
        <Child editable={this.props.editableOpts} />
      );
    } else {
      // In this case, Child will use the editableOpts from its own getDefaultProps()
      return (
        <Child />
      );
    }
  }
});

¿Hay alguna forma de escribir esto sin la declaración if? Estaba pensando en algo parecido a un tipo de declaración en línea en el JSX:

var parent = React.createClass({
  propTypes: {
    editable: React.PropTypes.bool.isRequired,
    editableOpts: React.PropTypes.shape({...})
  },
  render: function() {
    return (
      <Child 
        {this.props.editable ? editable={this.props.editableOpts} : null} 
      />
    );
  }
});

Para concluir : estoy tratando de encontrar una manera de definir un prop para Child, pero pasar un valor (o hacer algo más) de modo que Childaún extraiga el valor de ese prop del Childpropio getDefaultProps().

Matthew Herbst
fuente
¿Puedes incluir el código Childtambién? Además, ¿quiso decir en <Child editableOpts={this.props.editableOpts} />lugar de <Child editable={this.props.editableOpts} />?
Jim Skerritt
@JimSkerritt No confundí los accesorios, aunque sé que se ve así. Estoy tratando de usar react-bootstrap-tabley ese es el formato que usan. No estoy seguro de que el Childcódigo realmente importe para lo que estoy preguntando, por eso no lo incluí. Realmente solo estoy buscando una forma de pasar o no pasar opcionalmente un accesorio Childque no requiera tener una cantidad masiva de código similar en declaraciones if en Parent.
Matthew Herbst
1
Entendido, solo comprobando :) Tendré una respuesta en breve
Jim Skerritt

Respuestas:

141

Estuviste cerca de tu idea. Resulta que pasar undefinedpor un accesorio es lo mismo que no incluirlo en absoluto, lo que aún activará el valor de accesorio predeterminado. Entonces podrías hacer algo como esto:

var parent = React.createClass({
  propTypes: {
    editable: React.PropTypes.bool.isRequired,
    editableOpts: React.PropTypes.shape({...})
  },
  render: function() {
    return <Child 
      editable={this.props.editable ?
                  this.props.editableOpts : 
                  undefined}
    />;
  }
});
Jim Skerritt
fuente
¡Oh, genial! ¿Encontraste eso en alguna documentación? Estaba buscando eso pero no pude encontrar nada durante una búsqueda rápida
Matthew Herbst
No estoy seguro si está en la documentación o no, solo algo que aprendí mientras usaba React :)
Jim Skerritt
8
nullno está armado con un poder como undefined, por cierto.
Temporada
2
truco útil! Ojalá hubiera buenos recursos sobre cómo usar de manera efectiva las técnicas de renderizado condicional
nicodjimenez
1
En el falsecaso de que no me funcione como quería, todavía obtengo un par clave-valor property:: null. ¿Todavía es posible hacerlo de alguna manera con un solo elemento JSX?
Gal Grünfeld
25

Agregue un operador de propagación a this.props.editable:

<Child {...(this.props.editable ? {editable: {this.props.editableOpts}} : {})} >

Deberia trabajar.

Jamal Hussain
fuente
1
¿No produce el mismo resultado que editable = {this.props.editable? this.props.editableOpts: undefined} ¿O hay alguna diferencia?
garyee
1
@garyee: la diferencia es que algunos componentes pueden tratarse incorrectamente undefinedcomo una anulación (como null, que siempre es una anulación), por lo que la única forma de mantener el valor predeterminado en lugar de establecerlo en un valor falso es explícitamente no pasarlo, no pasar undefined.
Yann Dìnendal
@ YannDìnendal ¿qué pasa si utilizo un objeto vacío en lugar de indefinido, como <Child {... (this.props.editable? {Editable: {this.props.editableOpts}}: {)}> ¿Hace alguna diferencia? ¿cuál es mejor?
sktguha
1
@sktguha: sí, de hecho, parece un error tipográfico, creo: no podemos difundir sin definir, así que sí, debería ser un {}al final.
Sugeriré
16

Definir propsvariable:

let props = {};
if (this.props.editable){
  props.editable = this.props.editable;
}

Y luego úselo en JSX:

<Child {...props} />

Aquí hay una solución en su código:

var parent = React.createClass({
  propTypes: {
    editable: React.PropTypes.bool.isRequired,
    editableOpts: React.PropTypes.shape({...})
  },
  render: function() {
    let props = {};
    if (this.props.editable){
      props.editable = this.props.editable;
    }
    return (
      <Child {...props} />
    );
  }
});

Fuente, documentación de React: https://facebook.github.io/react/docs/jsx-in-depth.html#spread-attributes

Leon Gilyadov
fuente
Me gusta esta solucion Sin childPropsembargo
Daniel Reina
4

En realidad, si su prop es booleano, no es necesario implementar la condición, pero si desea agregar prop por condición en línea, debe escribir como se muestra a continuación:

const { editable, editableOpts } = this.props;
return (
  <Child {...(editable && { editable: editableOpts } )} />
);

Espero que no te confunda. el {...medio es operador extendido como pasar apoyos existentes: {...props}y el editable &&medio si editablees trueel { editable: editableOpts }objeto hará y con {...crearemos un nuevo objeto como este: {...{ editable: editableOpts }}eso significa editable={editableOpts}pero si this.porps.editablees verdadero.

AmerllicA
fuente
0
var parent = React.createClass({
  propTypes: {
    editable: React.PropTypes.bool.isRequired,
    editableOpts: React.PropTypes.shape({...})
  },
  render: function() {
    return (
      <Child 
        {...(this.props.editable && {editable=this.props.editableOpts})} 
      />
    );
  }
});

Esto pasa los apoyos si están definidos. De lo contrario, los accesorios no se pasan. En las otras respuestas, los accesorios todavía se pasan, pero el valor es undefinedque aún significa que se están pasando los accesorios.

sanair96
fuente
1
Pasar undefineda un accesorio es equivalente a no pasarlo en absoluto.
Matthew Herbst
Si entiendo. ¡Solo quería que quedara claro! ¡Gracias!
sanair96
0

también puedes probar esta forma corta

 <Child {...(this.props.editable  && { editable: this.props.editableOpts })} />
mortezashojaei
fuente