React のアプリで例えば編集モードの時にはフィールドで、そうでない時はテキストを表示するなど、条件によって表示を変えたい時など JSX 内で分岐をさせたい場合とか。 ふと思った。
JSXの中でif文使いたい場合って何がスタンダードなんだろう?
— 🌲🌲🌲 🌲🌲@芸カ18プ05 (@KiKiKi_KiKi) 2019年5月11日
JSXの中で {(() => { if {...} else {...} }()} って即時関数にするんはなんか違和感あるし、function foo() { if {...} else {...} } を作っておいて <Foo /> で呼び出すとかなんかな?
JSX 内で直接 if 文は使えない
JSX は { }
内で JavaScript が実行できるものだと思いこんでいたのですが、実行できるのは式 ( expression ) だけで、if
や for
のような文は実行できないようです。
if
statements andfor
loops are not expressions in JavaScript, so they can’t be used in JSX directly.
ref. JSX In Depth – React
直接 if 文を使おうとするとエラーになります
function Content(props) { return ( <div className="content"> { if (props.isEdit) { return ( <form onSubmit={props.onUpdate}> <input type="text" value={props.text} /> <button type="submit">UPDATE</button> </form> ) } else { return ( <p className="text">{props.text}</p> ) } } </div> ); }
=> Error:
Parsing error: Unexpected token`
即時関数内で if 文を使う
関数は JSX 内で実行できるので、即時関数を使ってその中で if 文で分岐させ出力するコンポーネントを return
する
function Content(props) { return ( <div className="content"> { !function() { if (props.isEdit) { return( <form onSubmit={props.onUpdate}> <input type="text" value={props.text} /> <button type="submit">UPDATE</button> </form> ); } else { return ( <p className="text">{props.text}</p> ); } }() } </div> ); }
Arrow 関数でもOK
function Content(props) { return ( <div className="content"> { (() => { if (props.isEdit) { return( ... ); } else { return ( ... ); } })() } </div> ); }
即時関数の注意点 最後に ;
があるとエラーになる
JSX 内で即時関数を使う場合、関数を実行する ()
に ;
が付いているとエラーになりるようです。
function Content(props) { return ( <div className="content"> { (() => { // ... })(); /* ↑ ; があるとエラーになる */ } </div> ); }
=> Parsing error: Unexpected token, expected "}"
三項演算子を使う
function Content(props) { return ( <div className="content"> { props.isEdit? (<form onSubmit={props.onUpdate}> <input type="text" value={props.text} /> <button type="submit">UPDATE</button> </form>) : (<p className="text">{props.text}</p>) } </div> ); }
三項演算子で直接 HTML を返すような書き方は、個人的に見通しが悪いように思うのであまり良くなさそうかなと思いました。出力する HTML を別コンポーネントにすればまだ見通しが立つように思います。
function InputField(props) { return ( <form onSubmit={props.onUpdate}> <input type="text" value={props.text} /> <button type="submit">UPDATE</button> </form> ); } function ContentBody(props) { return ( <p className="text">{props.text}</p> ); } function TestComponent(props) { return ( <div className="content"> { props.isEdit? (<InputField {...props} />) : (<ContentBody {...props} />) } </div> ); }
三項演算子の場合も即時関数のときと同じで最後に ;
があると Parsing error になる。
true の時だけ表示したいような場合は &&
が利用できる
JavaScript の比較演算子 &&
, ||
は Bool値を返すのではなく値を返すことを利用すれば、{(条件) && <trueの時に返される値>}
と書くことができます。
function TestComponent(props) { return ( <div className="content"> {props.isNew && (<span>NEW</span>)} // ... </div> ); }
note.
||
は 左辺がtrue
なら左辺を返し、左辺がfalse
なら右辺を返す&&
は 左辺がtrue
なら右辺を返し、左辺がfalse
なら左辺を返す
コンポーネントの形で関数を呼び出し、関数内で if 文などを使う
JSX の <Component />
という記法で Function Component を呼び出せているので、呼び出した関数内では通常の JavaScript が使用できるから、そこで分岐など行えば良い
function InputField(props) { return ( ... ); } function ContentBody(props) { return ( ... ); } function TestComponent(props) { const NewLabel = (isNew) => { if ( isNew ) { return (<span>NEW</span>); } } const Content = (props) => { if ( props.isEdit ) { return (<InputField {...props} />) } else { return (<ContentBody {...props} />) } } return ( <div className="content"> <NewLabel isNew={props.isNew} /> <Content {...props}/> </div> ); }
この方法が個人的には一番見通しが良くメンテナンスもしやすそうだなと思いました。
ポエム
JSX の { }
内で直接実行できるのは式 ( expression ) だけというのは、勘違いしてたので知れてよかったです。( どれが式なのかとかちゃんと理解できて入わけではないのですが…
Vue.js には v-if
や v-else
、 v-for
という制御するための構文が用意されていますが、もしかする JSX が構文使えないことを改善するために用意されたのかもなーと思いました。(属性で制御するのが見やすいかどうかは、あまり使ってないから何とも言えないし慣れの問題な気もする)
と、即時関数や三項演算子 &&
などを使えば JSX 内で分岐させる事もできるのですが、個人的に見通しが悪くなるように感じました。
React のチームが JSX 内で if
などの文を直接使えなくしているのは、構文を使わなければならないようなモノは別のコンポーネントにしろっていう思想なのではないかなー。と思ったのでした。
別件だけど Arrow関数の即時関数 !() => {}()
と書けないみたいなので、改めて調べたい。
[参考]

入門 React ―コンポーネントベースのWebフロントエンド開発
- 作者: Frankie Bagnardi,Jonathan Beebe,Richard Feldman,Tom Hallett,Simon HØjberg,Karl Mikkelsen,宮崎空
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/04/03
- メディア: 大型本
- この商品を含むブログ (2件) を見る