简体   繁体   中英

Conditionally linking with react-router Link

I have a situation in my React component which is: i want some elements to be wrappend in a Link component if this.props.isComingFromModal is false.

What i did (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>

But I this this is kind of repetitive. Can't I just do something like (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>

In this hypothetical scenario, i would exhibit the Link component just if this.props.isComingFromModal . There is a way to do something this?

You're right to want to try to avoid repetition in your JSX. I have a couple of strategies I use for this type of situation.

One option uses the fact that Link is just a ReactComponent object, and can be assigned to any variable. You can put a line like this at the beginning of your render method:

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

and then just render your content wrapped in the ConditionalLink component:

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

When your condition is true, ConditionalLink will be a reference to Link ; when the condition is false it will be a simple <div> .

Another option you might want to try is to create the content you want to render inside of the Link (or not inside the link) elsewhere, and then do essentially what you're doing above:

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

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

You could also create a function or method to return the content - or put it entirely in a new component.

Finally, to actually answer your question- Yes, you can make a link component that works the way you want! One of the great things about React is that it's really easy to remix existing components. If you want a conditional Link, just create a component that returns either {this.props.children} or <Link {...this.props}>{this.props.children}</Link> based on the value of a prop.

Maybe this is late, but despite evan's answer is correct, either of cases didn't work for me. Maybe due to some additional incorrect imports I've made or what... But it has inspired me to another similar solution, that worked just fine for me, so I want to share it here for those being in similar situation like me.

This solution will instead of putting the content into a variable rather create a simple ConditionalLink component that would accept any content as children with other required props but at least the condition and path to .

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

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

    return toRender;
}

Good thing on it is you could later reuse it again with any other content. For example:

<ConditionalLink condition={enabled && linkPath} to={linkPath}>
    ...content...
</ConditionalLink>

My simple functional solution:

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

Then you can use it like this:

<ConditionalLink to="/path" condition={!isComingFromModal}
  conditional link
</ConditionalLink>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM