Reactコンポーネントを条件付きでラップするにはどうすればよいですか?


90

私は時々としてレンダリングする必要がありますコンポーネント持ち<anchor>ようや他の回<div>。これpropを判断するために読んだのはthis.props.urlです。

存在する場合は、コンポーネントをでラップしてレンダリングする必要があります<a href={this.props.url}>。それ以外の場合は、としてレンダリングされます<div/>

可能?

これは私が今していることですが、単純化できると感じています。

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>
);

更新:

これが最後のロックアップです。先端をありがとう、@ 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;
    }
}

const baseClasses =そのif (this.props.link)ブランチに移動することもできます。あなたもしてビットを簡素化することができますので、あなたは、ES6を使用しているとしてconst {link, className} = this.props;、次に使用するlinkと、classNameローカル変数として。
スルタン2015年

男、私はそれが大好きです。ES6についてますます学ぶことで、常に読みやすさが向上します。追加のヒントをありがとう!
Brandon Durham

1
「最終ロックアップ」とは何ですか?
クリス・ハリソン

回答:


94

変数を使用するだけです。

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;

または、ヘルパー関数を使用してコンテンツをレンダリングできます。JSXは他のコードと同じです。重複を減らしたい場合は、関数と変数を使用してください。


23

要素をラップするためのHOC(高次コンポーネント)を作成します。

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はゆっくりと死ぬはずです:P
JamieHutber19年

この用語HOCは恐ろしいです。それは単に真ん中に置かれる関数です。私はこの突然流行の名前「HPC」を本当に置き換えます。何十年もの間古い概念の間に置かれている単純な関数について、何がそれほど高次であるか。
VSYNC

13

これは、私が使用した(誰に認定するかわからない)便利なコンポーネントの例です。

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

使用事例:

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

2
クレジットは、おそらくここに行く必要があります。gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
ロイ・プリンス

キッツェから見ました。しかし、彼が他の誰かからアイデアを得たかどうかは
わかり

私もそうではありません。これがポップアップした最初の結果であり、ソースであると想定しました-または少なくともそれに近い;)。
ロイプリンス

wrap物事をより「反応」させるための関数としてではなく、宣言的に使用する必要があります
精神

どのようにしてそれをより宣言的な@vsyncにしますか?レンダリング小道具はReactの精神の範囲内だと思いましたか?
アントニー

10

参照変数を使用できる別の方法があります

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>

)

あなたはに前半を凝縮することができますlet Wrapper = someCondition ? ParentComponent : React.Fragment
mpoisot

これは素晴らしいですが、コードを宣言型のままにしておきたい場合があります。つまり、JSXのみを返します
vsync 2010

「className」などのいくつかの小道具を「<Wrapper>」に渡すため、エラーが発生します React.Fragment can only have 'key' and 'children'
vsync 2010

@vsyncは、propId = {someCondition?のような小道具の条件を追加する必要があります。parentProps:undefined} ..
Avinash

1
私は知っています:)私はこの問題でここに来る他の人のためのドキュメントのためにこれを書いていたので、Googleはそれらのキーワードの検索結果にこのページをキャッシュします
vsync 2010

1

次のようなutil関数を使用することもできます。

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


0

ここで説明するように、JSXif-elseを使用する必要があります。このようなものが機能するはずです。

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

2つのコンポーネントをレンダリングする機能コンポーネント。1つはラップされ、もう1つはラップされません。

方法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>

これは、次のように使用することもできます。

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

方法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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.