Bir React bileşenini koşullu olarak nasıl sararım?


90

Bazen bir kılınmasını sağlamak için gereken bir bileşen var <anchor>bir şekilde ve diğer zamanlarda <div>. Bunu propbelirlemek için okudum this.props.url.

Varsa, bileşeni bir <a href={this.props.url}>. Aksi takdirde, yalnızca bir <div/>.

Mümkün?

Şu anda yaptığım şey bu, ancak basitleştirilebileceğini hissedin:

if (this.props.link) {
    return (
        <a href={this.props.link}>
            <i>
                {this.props.count}
            </i>
        </a>
    );
}

return (
    <i className={styles.Icon}>
        {this.props.count}
    </i>
);

GÜNCELLEME:

İşte son kilitlenme. İpucu için teşekkürler, @Sulthan !

import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';

export default class CommentCount extends Component {

    static propTypes = {
        count: PropTypes.number.isRequired,
        link: PropTypes.string,
        className: PropTypes.string
    }

    render() {
        const styles = require('./CommentCount.css');
        const {link, className, count} = this.props;

        const iconClasses = classNames({
            [styles.Icon]: true,
            [className]: !link && className
        });

        const Icon = (
            <i className={iconClasses}>
                {count}
            </i>
        );

        if (link) {
            const baseClasses = classNames({
                [styles.Base]: true,
                [className]: className
            });

            return (
                <a href={link} className={baseClasses}>
                    {Icon}
                </a>
            );
        }

        return Icon;
    }
}

Ayrıca const baseClasses =o if (this.props.link)şubeye de geçebilirsiniz . ES6'yı kullandığınız için, biraz da basitleştirebilir const {link, className} = this.props;ve ardından yerel değişkenler olarak linkve kullanabilirsiniz className.
Sulthan

Adamım, onu seviyorum. ES6 hakkında daha fazla bilgi edinmek ve her zaman okunabilirliği artırır. Ekstra ipucu için teşekkürler!
Brandon Durham

1
"Son kilitlenme" nedir?
Chris Harrison

Yanıtlar:


94

Sadece bir değişken kullanın.

var component = (
    <i className={styles.Icon}>
       {this.props.count}
    </i>
);

if (this.props.link) {
    return (
        <a href={this.props.link} className={baseClasses}>
            {component}
        </a>
    );
}

return component;

veya içeriği işlemek için bir yardımcı işlev kullanabilirsiniz. JSX, diğerleri gibi koddur. Yinelemeleri azaltmak istiyorsanız, işlevleri ve değişkenleri kullanın.


23

Öğenizi sarmak için bir HOC (üst düzey bileşen) oluşturun:

const WithLink = ({ link, className, children }) => (link ?
  <a href={link} className={className}>
    {children}
  </a>
  : children
);

return (
  <WithLink link={this.props.link} className={baseClasses}>
    <i className={styles.Icon}>
      {this.props.count}
    </i>
  </WithLink>
);

4
HOC yavaşça ölmeli: P
Jamie Hutber

Terim HOCiğrenç. Bu sadece ortaya yerleştirilen bir işlevdir. Bu aniden moda olan "HPC" adını gerçekten değiştirdim. arasına yerleştirilen basit bir işlevle ilgili bu kadar yüksek sıralama nedir ... on yıllardır eski konsept.
vsync

13

İşte kullandığım (onu kime akredite edeceğimi bilmiyorum) işe yarayan yararlı bir bileşene bir örnek:

const ConditionalWrap = ({ condition, wrap, children }) => (
  condition ? wrap(children) : children
);

Kullanım durumu:

<ConditionalWrap condition={someCondition}
  wrap={children => (<a>{children}</a>)} // Can be anything
>
  This text is passed as the children arg to the wrap prop
</ConditionalWrap>


Bunu Kitze'den gördüm. Ama fikri başka birinden aldığından emin değildim
antony

Ben de değilim. Bu ortaya çıkan ilk sonuçtu ve bunun kaynak olduğunu varsaydım - ya da en azından ona daha yakın;).
Roy Prins

Sen kullanmalıdır wrapfazla şeyler tutmak için bir fonksiyon olarak bildirimli değil -Ruh "Tepki"
vsync

Nasıl daha açıklayıcı @ vsync yaparsınız? Render dekorlarının React ruhu içinde olduğunu düşündüm.
antony

10

Referans değişkeni kullanmanın başka bir yolu var

let Wrapper = React.Fragment //fallback in case you dont want to wrap your components

if(someCondition) {
    Wrapper = ParentComponent
}

return (
    <Wrapper parentProps={parentProps}>
        <Child></Child>
    </Wrapper>

)

İlk yarıyılet Wrapper = someCondition ? ParentComponent : React.Fragment
mpoisot

Bu harika, ancak bazen kodu açıklayıcı tutmak istersiniz , yani yalnızca JSX döndürür
vsync

Bir hata alıyorum React.Fragment can only have 'key' and 'children' çünkü "<Wrapper>" a "className" gibi bazı sahne öğelerini iletiyorum ve benzeri
vsync

@vsync propId = {someCondition? gibi props için bir koşul eklemeniz gerekir. parentProps: undefined} ..
Avinash

1
Biliyorum :) Bunu, buraya bu sorunla gelen diğer kişiler için dokümantasyon amacıyla yazıyordum, bu nedenle Google, bu anahtar kelimelere ilişkin arama sonuçlarında bu sayfayı önbelleğe alacak
vsync

1

Bunun gibi bir kullanım işlevi de kullanabilirsiniz:

const wrapIf = (conditions, content, wrapper) => conditions
        ? React.cloneElement(wrapper, {}, content)
        : content;


0

Burada açıklandığı gibi bir JSX if-else kullanmalısınız . Bunun gibi bir şey çalışmalı.

App = React.creatClass({
    render() {
        var myComponent;
        if(typeof(this.props.url) != 'undefined') {
            myComponent = <myLink url=this.props.url>;
        }
        else {
            myComponent = <myDiv>;
        }
        return (
            <div>
                {myComponent}
            </div>
        )
    }
});

-2

Biri sarılı diğeri sarılmayan 2 bileşen oluşturan işlevsel bir bileşen.

Yöntem 1:

// The interesting part:
const WrapIf = ({ condition, With, children, ...rest }) => 
  condition 
    ? <With {...rest}>{children}</With> 
    : children

 
    
const Wrapper = ({children, ...rest}) => <h1 {...rest}>{children}</h1>


// demo app: with & without a wrapper
const App = () => [
  <WrapIf condition={true} With={Wrapper} style={{color:"red"}}>
    foo
  </WrapIf>
  ,
  <WrapIf condition={false} With={Wrapper}>
    bar
  </WrapIf>
]

ReactDOM.render(<App/>, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Bu da şu şekilde kullanılabilir:

<WrapIf condition={true} With={"h1"}>

Yöntem 2:

// The interesting part:
const Wrapper = ({ condition, children, ...props }) => condition 
  ? <h1 {...props}>{children}</h1>
  : <React.Fragment>{children}</React.Fragment>;   
    // stackoverflow prevents using <></>
  

// demo app: with & without a wrapper
const App = () => [
  <Wrapper condition={true} style={{color:"red"}}>
    foo
  </Wrapper>
  ,
  <Wrapper condition={false}>
    bar
  </Wrapper>
]

ReactDOM.render(<App/>, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.