web-dev-qa-db-ja.com

Facebook ReactのJSXで条件付き要素を持ちDRYを維持する方法

JSXにオプションで要素を含めるにはどうすればよいですか?これは、渡された場合にコンポーネント内にあるべきバナーを使用した例です。私が避けたいのは、ifステートメントでHTMLタグを複製する必要があることです。

render: function () {
    var banner;
    if (this.state.banner) {
        banner = <div id="banner">{this.state.banner}</div>;
    } else {
        banner = ?????
    }
    return (
        <div id="page">
            {banner}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}
224
Jack Allan

未定義であるとしてバナーを残すだけで、それは含まれません。

149
Jack Allan

これはどうですか。簡単なIfコンポーネントを定義しましょう。

var If = React.createClass({
    render: function() {
        if (this.props.test) {
            return this.props.children;
        }
        else {
            return false;
        }
    }
});

そしてこれを次のように使ってください。

render: function () {
    return (
        <div id="page">
            <If test={this.state.banner}>
                <div id="banner">{this.state.banner}</div>
            </If>
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

更新:私の答えが一般的になるにつれて、この解決策に関連した最大の危険性について警告する義務があると感じます。別の回答で指摘されているように、<If />コンポーネント内のコードは、条件が真か偽かにかかわらず常に実行されます。したがって、次の example は、bannernullの場合には失敗します(2行目のプロパティアクセスに注意してください)。

<If test={this.state.banner}>
    <div id="banner">{this.state.banner.url}</div>
</If>

使用するときは注意が必要です。私は別の(より安全な)アプローチのための他の答えを読むことを勧めます。

UPDATE 2:振り返ってみると、このアプローチは危険であるだけでなく、必然的に面倒です。これは、開発者(私)が自分の知っているパターンやアプローチをある領域から別の領域に転送しようとしたが、実際にはうまくいかない場合(この場合は他のテンプレート言語)の典型的な例です。

条件付き要素が必要な場合は、次のようにしてください。

render: function () {
    return (
        <div id="page">
            {this.state.banner &&
                <div id="banner">{this.state.banner}</div>}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

Else分岐も必要な場合は、三項演算子を使用してください。

{this.state.banner ?
   <div id="banner">{this.state.banner}</div> :
   <div>There is no banner!</div>
}

それはずっと短く、よりエレガントで安全です。私はいつも使っています。唯一の不利な点は、else if分岐を簡単に行うことができないということですが、通常はそれほど一般的ではありません。

とにかく、これはJavaScriptで 論理演算子 がどのように機能するかのおかげで可能です。論理演算子でも、次のような小さなトリックが可能です。

<h3>{this.state.banner.title || 'Default banner title'}</h3>
130
tobik

個人的には、三項表現は http://facebook.github.io/react/tips/if-else-in-JSX.html ReactJの標準に準拠する最も自然な方法です。

次の例を見てください。一見すると少し厄介ですが、かなりうまくいきます。

<div id="page">
  {this.state.banner ? (
    <div id="banner">
     <div class="another-div">
       {this.state.banner}
     </div>
    </div>
  ) : 
  null} 
  <div id="other-content">
    blah blah blah...
  </div>
</div>
81
Chiedo

あなたはまたそれを書くかもしれません

{ this.state.banner && <div>{...}</div> }

あなたのstate.bannernullまたはundefinedの場合、条件の右側はスキップされます。

45
wialy

Ifスタイルのコンポーネントは、条件に関係なくコードブロックが常に実行されるため危険です。たとえば、bannernullの場合、これはnull例外を引き起こします。

//dangerous
render: function () {
  return (
    <div id="page">
      <If test={this.state.banner}>
        <img src={this.state.banner.src} />
      </If>
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

もう1つの選択肢は、インライン関数を使用することです(elseステートメントで特に役立ちます)。

render: function () {
  return (
    <div id="page">
      {function(){
        if (this.state.banner) {
          return <div id="banner">{this.state.banner}</div>
        }
      }.call(this)}
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

反応からの別のオプション の問題

render: function () {
  return (
    <div id="page">
      { this.state.banner &&
        <div id="banner">{this.state.banner}</div>
      }
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}
41
bendytree

簡単です、関数を作ります。

renderBanner: function() {
  if (!this.state.banner) return;
  return (
    <div id="banner">{this.state.banner}</div>
  );
},

render: function () {
  return (
    <div id="page">
      {this.renderBanner()}
      <div id="other-content">
        blah blah blah...
      </div>
    </div>
  );
}

これは私が個人的にいつも従うパターンです。コードを本当にきれいにして理解しやすくします。さらに、それが大きすぎる(または他の場所で再利用される)場合は、Bannerを独自のコンポーネントにリファクタリングできます。

22

&& +コードスタイル+小さなコンポーネント

この簡単なテスト構文+コードスタイルの慣習+小さな集中的なコンポーネントは私にとってそこで最も読みやすいオプションです。 false0""のような偽の値には特別な注意を払う必要があります。

render: function() {
    var person= ...; 
    var counter= ...; 
    return (
       <div className="component">
          {person && (
            <Person person={person}/>
          )}
          {(typeof counter !== 'undefined') && (
            <Counter value={counter}/>
          )}
       </div>
    );
}

表記する

ES7のステージ0 do記法の構文もとても素敵です。私のIDEが正しくサポートしている場合は、これを使用します

const Users = ({users}) => (
  <div>
    {users.map(user =>
      <User key={user.id} user={user}/>
    )}
  </div>
)  

const UserList = ({users}) => do {
  if (!users) <div>Loading</div>
  else if (!users.length) <div>Empty</div>
  else <Users users={users}/>
}

詳細はこちら: ReactJs - "If"コンポーネントを作成するのが良い考えですか?

22

実験的なES7のdo構文は、これを簡単にします。 Babelを使用している場合は、es7.doExpressions機能を有効にします。

render() {
  return (
    <div id="banner">
      {do {
        if (this.state.banner) {
          this.state.banner;
        } else {
          "Something else";
        }
      }}
    </div>
  );
}

http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions を参照してください。

13
balexand

すでに回答で述べたように、JSXは2つの選択肢を提示します。

  • 三項演算子

    { this.state.price ? <div>{this.state.price}</div> : null }

  • 論理積

    { this.state.price && <div>{this.state.price}</div> }


しかし、それらはprice == 0では動作しません。

JSXは最初の場合はfalseブランチをレンダリングし、論理積の場合は何もレンダリングされません。プロパティが0になる可能性がある場合は、JSX以外のifステートメントを使用してください。

11
Lyubomir

このコンポーネントは "if"ブランチの中に複数の要素があるときに動作します。

    var Display = React.createClass({
        render: function() {
            if (!this.props.when) {
                return false;
            }
            return React.DOM.div(null, this.props.children);
        }
    });

使用法:

      render: function() {
            return (
                <div>
                    <Display when={this.state.loading}>
                        Loading something...
                        <div>Elem1</div>
                        <div>Elem2</div>
                    </Display>
                    <Display when={!this.state.loading}>
                        Loaded
                        <div>Elem3</div>
                        <div>Elem4</div>
                    </Display>
                </div>
            );
        },

PSこのコンポーネントはコードの読み取りには適していないと考える人がいます。しかし、私の心の中ではJavaScriptを使ったhtmlはもっと悪いです

8
k.makarov

ほとんどの例は、条件付きでレンダリングされる1行の "html"を使用しています。条件付きでレンダリングする必要がある複数の行がある場合、これは私には分かりやすいようです。

render: function() {
  // This will be renered only if showContent prop is true
  var content = 
    <div>
      <p>something here</p>
      <p>more here</p>
      <p>and more here</p>
    </div>;

  return (
    <div>
      <h1>Some title</h1>

      {this.props.showContent ? content : null}
    </div>
  );
}

nullの代わりに{this.props.showContent ? content : otherContent}のような他のコンテンツを条件付きでレンダリングできるので、最初の例は良いです。

ただし、コンテンツを表示/非表示にする必要がある場合は、 Booleans、Null、およびUndefinedが無視されるため 、これはさらに優れています。

render: function() {
  return (
    <div>
      <h1>Some title</h1>

      // This will be renered only if showContent prop is true
      {this.props.showContent &&
        <div>
          <p>something here</p>
          <p>more here</p>
          <p>and more here</p>
        </div>
      }
    </div>
  );
}
3
ivn

私はもっ​​と明示的なショートカットを使用します。即時起動関数式(IIFE):

{(() => {
  if (isEmpty(routine.queries)) {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  } else if (this.state.configured) {
    return <DeviceList devices={devices} routine={routine} configure={() => this.setState({configured: false})}/>
  } else {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  }
})()}
2
jsdario

別の解決策、 if component for React があります。

var Node = require('react-if-comp');
...
render: function() {
    return (
        <div id="page">
            <Node if={this.state.banner}
                  then={<div id="banner">{this.state.banner}</div>} />
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}
2
Gordon Freeman

本当にきれいな一行バージョンもあります...{this.props.product.title || "タイトルなし"}

すなわち:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }
1
max kaplan

これが私のES6を使ったアプローチです。

import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';

class ToggleBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // toggle box is closed initially
      opened: false,
    };
    // http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
    this.toggleBox = this.toggleBox.bind(this);
  }

  toggleBox() {
    // check if box is currently opened
    const { opened } = this.state;
    this.setState({
      // toggle value of `opened`
      opened: !opened,
    });
  }

  render() {
    const { title, children } = this.props;
    const { opened } = this.state;
    return (
      <div className="box">
        <div className="boxTitle" onClick={this.toggleBox}>
          {title}
        </div>
        {opened && children && (
          <div class="boxContent">
            {children}
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render((
  <ToggleBox title="Click me">
    <div>Some content</div>
  </ToggleBox>
), document.getElementById('app'));

デモ: http://jsfiddle.net/kb3gN/16688/

私は次のようなコードを使っています:

{opened && <SomeElement />}

SomeElementがtrueの場合のみ、それはopenedをレンダリングします。 JavaScriptが論理条件をどのように解決するかによって、うまくいきます。

true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise

Reactfalseを無視するので、いくつかの要素を条件付きでレンダリングするのはとても良い方法です。

1
pie6k

次のように三項演算子を使用して条件付きで要素を含めることができます。

render: function(){

         return <div id="page">

                  //conditional statement
                  {this.state.banner ? <div id="banner">{this.state.banner}</div> : null}

                  <div id="other-content">
                      blah blah blah...
                  </div>

               </div>
}
1
mada-g

私は https://www.npmjs.com/package/jsx-control-statements を作成してそれをもう少し簡単にします、基本的にそれはあなたが定義することを可能にします<If>条件式をタグとして使用し、それらを3進数ifにコンパイルして、<If>内のコードが条件が真の場合にのみ実行されるようにします。

1
Alex Gilleran

多分それは質問に遭遇する誰かを助ける: Reactのすべての条件付きレンダリング Reactの条件付きレンダリングのためのすべての異なるオプションに関する記事です。

どの条件付きレンダリングを使用するかについての主な注意事項

** if-else

  • 最も基本的な条件付きレンダリングです
  • 初心者に優しい
  • nullを返すことにより、レンダリングメソッドから早期にオプトアウトする場合に使用します。

**三項演算子

  • if-else文に使用します
  • if-elseよりも簡潔です

**論理的な&&演算子

  • 三項演算の一方がnullを返す場合に使用します

** スイッチケース

  • 冗長な
  • 自己呼び出し関数でのみインライン化できます
  • それを避け、代わりにenumを使ってください

**列挙

  • さまざまな州をマッピングするのに最適
  • 複数の条件をマッピングするのに最適

**マルチレベル/ネスト条件付きレンダリング

  • 読みやすくするためにそれらを避けてください
  • 独自の単純な条件付きレンダリングを使用して、コンポーネントをより軽量のコンポーネントに分割する
  • hOCを使用する

** HOC

  • 条件付きレンダリングをシールドするためにそれらを使う
  • コンポーネントはその主な目的に焦点を合わせることができます

**外部テンプレートコンポーネント

  • それらを避けてJSXとJavaScriptに慣れてください
1
Robin Wieruch

要素を安全にレンダリングするために、最近私は https://github.com/ajwhite/render-if を作成しました述語はを渡します。

{renderIf(1 + 1 === 2)(
  <span>Hello!</span>
)}

または

const ifUniverseIsWorking = renderIf(1 + 1 === 2);

//...

{ifUniverseIsWorking(
  <span>Hello!</span>
)}
1
Atticus

関数を使用してコンポーネントを返し、レンダリング関数を薄くしておくことができます。

class App extends React.Component {
  constructor (props) {
    super(props);
    this._renderAppBar = this._renderAppBar.bind(this);
  }

  render () {
    return <div>
      {_renderAppBar()}

      <div>Content</div>

    </div>
  }

  _renderAppBar () {
    if (this.state.renderAppBar) {
      return <AppBar />
    }
  }
}
1
pedronalbert

ES6では、シンプルなワンライナーでそれを実現できます

const If = ({children, show}) => show ? children : null

"show"はブール値なので、このクラスを使用します。

<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>
1
Leon

コンポーネントを条件付きでレンダリングするには、レンダリングプロップを使用する方法もあります。利点は、条件が満たされるまでレンダリングが評価されないため、nullおよびの未定義値を心配する必要がないことです。

const Conditional = ({ condition, render }) => {
  if (condition) {
    return render();
  }
  return null;
};

class App extends React.Component {
  constructor() {
    super();
    this.state = { items: null }
  }

  componentWillMount() {
    setTimeout(() => { this.setState({ items: [1,2] }) }, 2000);
  }

  render() {
    return (
      <Conditional
        condition={!!this.state.items}
        render={() => (
          <div>
            {this.state.items.map(value => <p>{value}</p>)}
          </div>
        )}
      />
    )
  }
}
0
Farzad YZ

私はこれが言及されているとは思わない。これはあなた自身の答えのようですが、私はそれがさらに簡単だと思います。あなたはいつでも式から文字列を返すことができ、式の中にjsxをネストすることができるので、これは読みやすいインライン式を可能にします。

render: function () {
    return (
        <div id="page">
            {this.state.banner ? <div id="banner">{this.state.banner}</div> : ''}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpf1/t39.3284-6/10574688_1565081647062540_1607884640_n.js"></script>
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpa1/t39.3284-6/10541015_309770302547476_509859315_n.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";

var Hello = React.createClass({
  render: function() {
    return (
      <div id="page">
        {this.props.banner ? <div id="banner">{this.props.banner}</div> : ''}
        <div id="other-content">
          blah blah blah...
        </div>
      </div>
    );   
  }
});

var element = <div><Hello /><Hello banner="banner"/></div>;
React.render(element, document.body);

}()</script>
0
Juan Mendes

渡された条件が満たされている場合にのみ何かをレンダリングする必要がある場合は、次の構文を使用できます。

{ condition && what_to_render }

この方法のコードは次のようになります。

render() {
    const { banner } = this.state;
    return (
        <div id="page">
            { banner && <div id="banner">{banner}</div> }
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

もちろん、これを行うための有効な方法は他にもあります。それはすべて、設定とオカレンス次第です。興味があれば、 この記事 でReactで条件付きレンダリングを行う方法についてもっと学ぶことができます。

0
Nesha Zoric

if-elserender callbacksよりも、即時呼び出し関数式(IIFE)とternary operatorsの明示性が好きです。

render() {
  return (
    <div id="page">
      {(() => (
        const { banner } = this.state;
        if (banner) {
          return (
            <div id="banner">{banner}</div>
          );
        }
        // Default
        return (
          <div>???</div>
        );
      ))()}
      <div id="other-content">
        blah blah blah...
      </div>
    </div>
  );
}

あなたはIIFE構文に精通している必要があります、{expression}は普通のReact構文です、その中でそれ自身がそれ自身を呼び出す関数を書いていると考えてください。

function() {

}()

それは括弧の中に包む必要がある

(function() {

}())
0