はじめに
今日、インターン先オフィスでReactを勉強しているデザイナーさん2人と話していたところ、JSX内の条件文についてまとめ記事があったらいいよねという話になったので淡々とまとめていきたいと思います。簡潔にまとめたいので、前置きはこの辺にして早速始めます。
そもそもJSXってなに?
JSXとは、まるでHTMLを書いているかのようにReactを書くために作られたものです。なので
return (
<div>
<h1>僕のホームページ</h1>
</div>
)
詳しいことは割愛しますが、この**return()
内のタグは実際にはHTMLのタグではないです。**
return()
内に来るのはHTMLのコードではなくJSXなので、たとえば
const hoge = 'fuga'
return (
<div>
<p>{hoge}</p>
</div>
)
このように{}で囲むことによって、JSX内に直接JavaScript
で定義した変数や定数(なんなら返り値のある関数でも)つっこむことができます。
その結果、上のコードから実際には
<div>
<p>fuga</p>
</div>
というHTMLタグが生成されることになります。
本題:if文はJSXの中で書け
ReactでWeb開発をする際、次のような実装をする場面が出てくると思われます。
props
にてicon
が定義されている場合のみ、ラベルとともにアイコンも表示するようなボタンを実装したい
普通のif文しか知らなかった頃の僕は、このような書き方をしていました。(お恥ずかしい、、笑)
const HogeComponent = ({ icon, label }) => { // propsはこのように{}で囲んだ中に直接定義することもできる
if (icon === undefined) { // iconが渡されていない場合
return (
<button>
{label}
</button>
)
} else {
return (
<button>
{icon}
{label}
</button>
)
}
}
これ、iconを表示するかしないかだけの違いなのに同じことを2回書いてしまっています。
では、if文をJSXの中で書いてみましょう。
const HogeComponent = ({ icon, label }) => {
return (
<button>
{icon && <img src={icon} alt='icon' />}
{label}
</button>
)
}
随分とすっきり書けました。
なぜこのように書けるのか少し掘り下げてみましょう。
{icon && <img src={icon} alt='icon' />}
ここに注目します。
これこそがJSX内のif文(正確にいうと条件式)で、iconは左辺、&&の後は右辺と呼ばれます。
この文は、左辺(つまり条件部分)がtrue
であるときは右辺を、そうでないときは左辺を返します。
icon
の中身は、
- 定義されている時・・・画像データ
- 定義されていない時・・・
undefined
でした。
つまりアイコンが定義されているときは<img />
タグ、定義されていない場合はundefined
が返されています。
ここからが重要です。
JSX内でundefined
やfalse
、true
、null
などが返された場合、Reactはそれらを完全に無視します。
つまりは何もレンダー(描画)しません。
ここに関して、僕は長い間勘違いをしていました。上の条件式について、単純に条件おいて&&の後に描画したいコンポーネントおけばいいんでしょ?くらいにしか思っていませんでした。そのため、条件の部分にはtrue
かfalse
をとるものしか置いてきませんでした。
このような内部的な動きに関しても理解を深めておくことはとても重要なんだなと改めて認識した出来事でした。
左辺を返り値にしたくない場合
条件を満たさない場合でも左辺を返り値にしてしまいたくないとき、次のような書き方ができます。
const HogeButton = ({ primary, label }) => {
return (
<button>
{primary
? <div className='primaryButtonInner'>{label}</div>
: <div className='normalButtonInner'>{label}</div>
}
</button>
)
}
ボタンがprimary
なのかどうかをtrue
かfalse
で渡されて、それに応じてボタンのインナーのスタイルを変えたいという場面です。
これは三項演算子と言います。primaryが真のとき?以降が、そうでないとき:以降が返されます。
(2020/10/2更新)
@thomasJs8 さんよりコメントをいただきました。
下の補足にもありますが、三項演算子は様々なところで使えるのでこのようにも書けます。
const HogeButton = ({ primary, label }) => {
return (
<button>
<div className={ primary ? 'primaryButtonInner' : 'normalButtonInner' }>{label}</div>
</button>
)
}
条件分岐による影響範囲の大小により、どの範囲に三項演算子を適用するか都度考えて実装すると無駄のない綺麗なコードを書くことができます。
今回の内容には直接関係のない補足ですが、
const HogeFunction = ({ active }) => {
const result = (active) ? 'hoge' : 'fuga'
return result
}
三項演算子は上のようにJSX内以外でも使えます。(当たり前ですが)
この場合active === true
のとき文字列hogeが、active === false
のとき文字列fugaが返されます。
この書き方のいいところは、
const HogeFunction = ({ active }) => {
if (active) {
const result = 'hoge'
} else {
const result = 'fuga'
}
return result // undefined
}
このようなスコープの違いにより実現できないコードを解決してくれることです。
それぞれのresult
は{}で囲まれている、つまり、それぞれ閉鎖的なスコープに閉じ込められているため、スコープの外からは見えません。
そのため、HogeFunction
はactive
の値と関係なくundefined
を返します。
(2020/10/2更新)
ここに関しても、@thomasJs8 さんよりコメントをいただきました。
ここで宣言している定数result
をreturn
するわけではない時は三項演算子を使うのが賢明ですが、return
してしまいたい時
const HogeFunction = ({ active }) => {
if (active) {
return 'hoge'
} else {
return 'fuga'
}
}
とif文内でreturn
することもできます。
最後に
今回紹介した書き方は、わりと既に広く使われているものだと思います。しかし、内部的にどのように動いているのか深く掘り下げて考えてみることに価値があると思い、まとめて投稿してみました。この記事が皆さんのReactに対する深い理解の一助になれば幸いです。
参考リンク
- 条件付きレンダー
- JSXを深く理解する