Tengo una situación en mi componente Reaccionar que es: quiero que algunos elementos se envuelvan en un componente Link si this.props.isComingFromModal es falso.

Lo que hice (JSX):

<If condition={!this.props.isComingFromModal}>
  <Link
    to={{ pathname: `vendors/${benefit.vendor.id}`, state: { modal: false } }}
  >
    <img
      className="Benefit__vendor__thumb"
      src={benefit.vendor.tinyLogoUrl}
      alt="Ponto Frio"
    />


    <div className="Benefit__vendor__info">
      <h2 className="Benefit__vendor__title">{benefit.vendor.tradingName}</h2>
      <div className="rating">
        <Rating
          readonly
          initialRate={benefit.vendor.rating}
          className="rating"
          fractions={2}
          empty="icon-rating icon-rating--empty fa fa-star fa-2x"
          full="icon-rating fa fa-star fa-2x"
        />
      </div>
    </div>
  </Link>
  <Else />
    <img
      className="Benefit__vendor__thumb"
      src={benefit.vendor.tinyLogoUrl}
      alt="Ponto Frio"
    />


    <div className="Benefit__vendor__info">
      <h2 className="Benefit__vendor__title">{benefit.vendor.tradingName}</h2>
      <div className="rating">
        <Rating
          readonly
          initialRate={benefit.vendor.rating}
          className="rating"
          fractions={2}
          empty="icon-rating icon-rating--empty fa fa-star fa-2x"
          full="icon-rating fa fa-star fa-2x"
        />
      </div>
    </div>
</If>

Pero esto es algo repetitivo. ¿No puedo hacer algo como (JSX)

<Link
  to={{ pathname: `vendors/${benefit.vendor.id}`, state: { modal: false } }}
  condition={!this.props.isComingFromModal}
>
  <img
    className="Benefit__vendor__thumb"
    src={benefit.vendor.tinyLogoUrl}
    alt="Ponto Frio"
  />


  <div className="Benefit__vendor__info">
    <h2 className="Benefit__vendor__title">{benefit.vendor.tradingName}</h2>
    <div className="rating">
      <Rating
        readonly
        initialRate={benefit.vendor.rating}
        className="rating"
        fractions={2}
        empty="icon-rating icon-rating--empty fa fa-star fa-2x"
        full="icon-rating fa fa-star fa-2x"
      />
    </div>
  </div>
</Link>

En este escenario hipotético, exhibiría el componente Enlace solo si this.props.isComingFromModal. ¿Hay alguna manera de hacer algo así?

7
Filipe Merker 13 may. 2016 a las 23:25

3 respuestas

La mejor respuesta

Tienes razón al tratar de evitar la repetición en tu JSX. Tengo un par de estrategias que uso para este tipo de situación.

Una opción utiliza el hecho de que Link es solo un objeto ReactComponent y puede asignarse a cualquier variable. Puede poner una línea como esta al comienzo de su método render:

var ConditionalLink = !this.props.isComingFromModal ? Link : React.DOM.div;

Y luego simplemente renderice su contenido envuelto en el componente ConditionalLink:

return (
    <ConditionalLink>
        <img />
        <div>...</div>
    </ConditionalLink>
);

Cuando su condición sea verdadera, ConditionalLink será una referencia a Link; cuando la condición es falsa, será un simple <div>.

Otra opción que puede intentar es crear el contenido que desea representar dentro del Enlace (o no dentro del enlace) en otro lugar, y luego hacer esencialmente lo que está haciendo arriba:

var content = (
    <div>
        <img />
        <div>All your content</div>
    </div>
);

return (<If condition={!this.props.isComingFromModal}>
    <Link>
        {content}
    </Link>
    <Else />
    {content}
</If>);

También puede crear una función o método para devolver content, o ponerlo completamente en un nuevo componente.

Finalmente, para responder realmente a su pregunta: ¡Sí, puede crear un componente de enlace que funcione de la manera que desee! Una de las mejores cosas de React es que es muy fácil remezclar componentes existentes. Si desea un enlace condicional, simplemente cree un componente que devuelva {this.props.children} o <Link {...this.props}>{this.props.children}</Link> en función del valor de un accesorio.

5
evan 14 may. 2016 a las 05:47

Tal vez esto sea tarde, pero a pesar de que la respuesta de evan es correcta, ninguno de los casos no funcionó para mí. Tal vez debido a algunas importaciones incorrectas adicionales que he hecho o qué ... Pero me ha inspirado a otra solución similar, que funcionó bien para mí, así que quiero compartirla aquí para aquellos que están en una situación similar como yo.

Esta solución, en lugar de poner el contenido en una variable, creará un componente simple ConditionalLink que acepte cualquier contenido como children con otros accesorios necesarios, pero al menos el condition y la ruta {{X3 }}.

render() {
    const {children, to, condition} = this.props;
    let toRender;

    if (condition) {
        toRender = <Link to={to}>{children}</Link>;
    } else {
        toRender = children;
    }

    return toRender;
}

Lo bueno es que más tarde podría reutilizarlo nuevamente con cualquier otro contenido. Por ejemplo:

<ConditionalLink condition={enabled && linkPath} to={linkPath}>
    ...content...
</ConditionalLink>
2
Kuba 9 oct. 2018 a las 10:45

Mi solución funcional simple:

const ConditionalLink = ({ children, to, condition }) => (!!condition && to)
      ? <Link to={to}>{children}</Link>
      : <>{children}</>;

Entonces puedes usarlo así:

<ConditionalLink to="/path" condition={!isComingFromModal}
  conditional link
</ConditionalLink>
2
Max Starling 23 may. 2019 a las 15:34