クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【React】条件分岐の書き方(if文エラー回避、論理演算子、三項演算子)

Reactの続きです。前回ではJSXで関数の入れ子をやってみました。今回からは制御構造に入って行きます。まずは分岐から。JSXはif文をそのまま書くとエラーになるという衝撃の事実から、回避方法をご紹介。論理演算子(&&!)、三項演算子(?:)で書く方法も。それでは行きましょう!

【目次】

前回の記事
※参考:【React】JSXの中に別の関数のJSXを読み込む(入れ子状態) - クモのようにコツコツと

Reactを習得するためにやったことまとめ
qiita.com

ReactのJSXではif文が書けない!?

React習得、掌田さんの「React.js & Next.js超入門」を参考に進めていて、制御構造(分岐、反復)に進んだ。

React.js&Next.js超入門

React.js&Next.js超入門

ここで疑問に思ったのがReactの制御構造としてif文(分岐)やfor文(反復)を使わない書き方を紹介していること。

調べるてみるとなんと、Reactが採用しているJSXではif文やfor文が書けないらしい!?

if statements and for loops are not expressions in JavaScript, so they can’t be used in JSX directly.

「ifステートメントとforループはJavaScriptの式ではないため、JSXで直接使用することはできません。」

※参考:JSX In Depth – React

「JavaScriptの式ではない」え?いや、そ、そうなのかい?JSの式だと思うのだが。。

まあ確かにC言語やJavaなども同じ書き方なので「JSの式です!」とは言い切れないのかも知れないが、それがJSXで使えない理由になるのがよくわからない…。

JSXにif文を直書きしてみる(結果、エラー。。)

本当かどうか、確かめてみる。JSXの中にif文を直接書いてみた。

See the Pen React 10 if-ng by イイダリョウ (@i_ryo) on CodePen.

結果としては、JSXが動いてない。「読み込み中」となっていると言うことはそう言うことだ。本当だ…。

ちなみに書いたコードはこちら。

HTMLコード

<section>
    <h1>楽しい楽しいお店</h1>
    <div class="text">読み込み中…</div>
</section>

.textには初期値として「読み込み中…」と言うテキストを入れており、このタグをReactで書き換えている。このテキストが表示されている=Reactが動いていないと言うことだ。

JSコード

//DOM取得
const text = document.querySelector('.text');

//JSXに埋め込む値
const h2Text = "楽しい楽しいお店にようこそ!";
const pText = "(18歳以上の方がお楽しみいただけます)";

const okMsg = "ようこそ!ご入場ください。";
const ngMsg = "お引き取りください。";

const age = 35;

//JSXの中身
const elm = (
<section className="h2_elem">
    <h2>{ h2Text }</h2>
    <p>{ pText }</p>
    {
        if ( age >= 18 ) {
            <p>{ okMsg }</p>        
        } else {
            <p>{ ngMsg }</p>    
        }
    }
</section>
);

//レンダリング
ReactDOM.render(elm, text);
  • 変数text.textのDOMを取得
  • 変数h2Texth2タグに表示したいテキスト
  • 変数pTextpタグに表示したいテキスト
  • 変数okMsgは条件分岐で条件がOKなときに表示したいテキスト
  • 変数ngMsgは条件分岐で条件がNGなときに表示したいテキスト
  • 変数ageは条件として入れる値35
  • 変数elmでJSXを設定
    h2タグにh2Textを読み込み
    pタグにpTextを読み込み
    if文ageが18以上であればokMsgを表示
    さもなくばngMsgを表示
  • ReactDOM.renderelmをレンダリングしてtextに返す

「楽しい楽しいお店」の入り口で年齢制限を設けている(R18)。
ageの値が35なのでokMsgの「ようこそ!ご入場ください。」が表示されることを期待していたが、Reactが丸ごと動いてない。

if文を即時関数に入れる

これを回避する方法として、まずir文を即時関数に入れる方法がある。

※参考:React JSX の中で if で分岐させたい - かもメモ

即時関数はこのような書き方。

//即時関数
(()=> {
    //処理
 })();

これを使うメリットはスコープ汚染を防ぐこと。即時関数の中に書いた変数名は外の変数名と被っても干渉しない。

※参考:JavaScriptで即時関数を使う理由 - Qiita

以前、Tone.jsでも変数iを即時関数に入れて解決したことがある。

※参考:【Tone.js】3コード楽器のコードをリファクタリング(ループとイベントと即時関数) - クモのようにコツコツと

これを使うとJSXの中でもif文が動くようだ。やってみる。

See the Pen React 11 if-ok by イイダリョウ (@i_ryo) on CodePen.

おお!期待通りに表示された!

35歳なので「ようこそ!ご入場ください。」と表示されてる!Reactでif文、動きまぁす♪

JSコード

//JSXの中身
const elm = (
<section className="h2_elem">
    <h2>{ h2Text }</h2>
    <p>{ pText }</p>
        {(() => {
            if ( age >= 18 ) {
                return <p>{ okMsg }</p>     
            } else {
                return <p>{ ngMsg }</p> 
            }
        })()}
</section>
);
  • if文を即時関数で囲う。
  • JSXはreturnで返す

ただ、即時関数自体もブロック{ }で囲っているので、かなりカッコが重複して直感的じゃないねw

※2020/03/04追記

なお、if文の中のJSXにreturnを付けないとJSXは表示されなかった!

See the Pen React 11 if-ng2 by イイダリョウ (@i_ryo) on CodePen.

pタグまでのJSXは反映されたが、その下のif文から先が反映されていない。

       {(() => {
            if ( age >= 18 ) {
                <p>{ okMsg }</p>      
            } else {
                <p>{ ngMsg }</p>  
            }
        })()}

returnによってJSコードとJSXのhtmlタグの境界を識別できるようだ。

if文をJSX外部の関数として書く

前回の記事でやったように、外部に関数を書いて、それをJSXの中に組み込むのもいけそうなのでやってみる。

※参考:【React】JSXの中に別の関数のJSXを読み込む(入れ子状態) - クモのようにコツコツと

See the Pen React 12 if-ok by イイダリョウ (@i_ryo) on CodePen.

おお、これもまた動いた!

JSコード

const msg = () => {
    if ( age >= 18 ) {
        return <p>{ okMsg }</p>     
    } else {
        return <p>{ ngMsg }</p> 
    }
}

//JSXの中身
const elm = (
<section className="h2_elem">
    <h2>{ h2Text }</h2>
    <p>{ pText }</p>
    { msg() }
</section>
);
  • 変数msgに無名関数を代入してif文の処理をかく
  • pタグの後にmsg()を読み込む

JSXの中に書かなければ問題ないと言うことか。

論理演算子&&で書く

掌田さんの本ではif文以外の方法が紹介されていて、1つ目は論理演算子&&を使う方法。

論理演算子は「AかつB(&&)」「AまたはB(||)」「A以外!」など。よく、if文やfor文の条件式の中で複数の条件を指定するときに使ったりする。

※参考:論理演算子 - JavaScript | MDN

これを使ってif文のような条件分岐をできるんだなー。やってみよう。

See the Pen React 13 Branch-1 by イイダリョウ (@i_ryo) on CodePen.

おお、動いた!

JSコード

//JSXの中身
const elm = (
<section className="h2_elem">
    <h2>{ h2Text }</h2>
    <p>{ pText }</p>
        {   age >= 18 && <p>{ okMsg }</p>   }
        {   !age >= 18 && <p>{ ngMsg }</p> }
</section>
);
  • elmpタグの次に論理演算子で式を書いている
  • ageが18以上がtrueならばpタグにokMsgを表示
  • ageが18以上がtrueじゃなければ(!pタグにngMsgを表示

&&の前が条件となり、結果がtrueの時だけ値を返す。elseが無いif単独の条件分岐(それ以外は何もしない)に使われる。

条件の頭に!を付けることで、trueじゃない場合、と言う条件になる。こういう書き方は普段しないので新鮮!

if文は使えないけど演算子は普通に使えるため、JSXの中で条件分岐を設定できる、と言うわけか。

三項演算子?:で書く

もう一つ、三項演算子でも書くことができる。

三項演算子はVue.jsでTodoリストを作ったときに書いた。

※参考:【Vue.js】localStorageと連携したTodoリストを読み解く(JS編-3) - クモのようにコツコツと

このような書き方。

条件 ? trueの場合の処理 : falseの場合の処理

※参考:条件 (三項) 演算子 - JavaScript | MDN

なお、分岐が2択ではない場合も、分岐を繰り返し書くことによって指定ができるようだ。

※参考:このくらいまでならjsで三項演算子使ってもいいよね、っていうパターン(個人的に) - Qiita

やってみた。

See the Pen React 14 Branch-2 by イイダリョウ (@i_ryo) on CodePen.

やた!これも動いた。

JSコード

//JSXの中身
const elm = (
<section className="h2_elem">
    <h2>{ h2Text }</h2>
    <p>{ pText }</p>
        {   age >= 18 ? <p>{ okMsg }</p>
        :   <p>{ ngMsg }</p> 
        }
</section>
);
  • pタグの後に三項演算子を書いている
  • age18以上か(?)、trueならpタグにokMsgを表示
    falseならpタグにngMsgを表示

この書き方の方が先程の論理演算子(&&!)よりも重複がなくてスマート。

ただ、スマートすぎて?:の一文字を見逃す可能性もありそうw

最後に

と言うことでJSXで条件分岐をするいくつかの方法を試してみました。どの方法でも結果は同じなので、お好みということになるかと思います。個人的にはこのように感じました。

方法 備考
即時関数にif文 JSXの構造が膨らむので直感的じゃない?閉じカッコが重なっている部分も間違えそう。
外部の関数にif文 それぞれの関数の中がシンプルなので見通しは良さそう。
論理演算子(&&! !を使った分岐は重複するのでelseがないif単独の分岐に良さそう
三項演算子(?: 処理の行数が少ない簡単な条件分岐ならこれで済ませても良さそう。見逃し注意!

次回は反復をやってみます。こちらもJSXの中にfor文を直接書くことが出来なそうです。それではまた!


Reactを習得するためにやったことまとめ
qiita.com