【JS】Reactのループを逆順にする方法いろいろ
こんにちは!深夜にReact書くと型が適当になりがち。Mizutani(@sirycity)です。anyany~
今日はReactでめっちゃ使う(というかDOMの描画で使う)ループを反対にする方法について色々書きます。
はじめに
Reactのループ、基本的にはこんな感じです。これが基本系。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
<ul>
{
arr.map((e, i) =>
<li key={i}>{e}</li>
)
}
</ul>
}
これは実際にはこんな感じになる↓
<ul>
<li>さいしょ</li>
<li>つぎ</li>
<li>さいご</li>
</ul>
すごいシンプルね。でも、逆順にしたい時もあるでしょ?こんな感じに↓
<ul>
<li>さいご</li>
<li>つぎ</li>
<li>さいしょ</li>
</ul>
この方法について考えていきます。
逆順にする方法いろいろ
reverseを使う
一番簡単なのが.reverse()を使う方法…
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
// 逆にする
const reversedArr = arr.reverse()
<ul>
{
reversedArr.map((e, i) =>
<li key={i}>{e}</li>
)
}
</ul>
}
いやこれで良いと思うじゃん?ダメなんだよなこれが。これで良かったら記事にしてない
有名な話ですが、JSのreverseは破壊的変更のため、Reactとの相性が最悪です。というか現代のJSとの相性が最悪。具体的には順番がでたらめになる可能性があります。どういう時になるかはあんま詳しくないけど。非破壊的なreverseはJS界隈で待ち望まれている機能の一つですね。
reduceRightを使う
.reduceRight()を使って配列をひっくり返すのはわりとベターな方法です。こう。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
// 逆にする
const reversedArr = arr.reduceRight((p, c) => [...p, c], [])
<ul>
{
reversedArr.map((e, i) =>
<li key={i}>
{ e }
</li>
)
}
</ul>
}
reduceRight、いつ使うんだ?って思っていたあなた。非破壊的に配列をひっくり返すこんな使い方があるんです!すごい!…ただ、reduce本来の使い方とは異なるので列が長くなってくると重い。ここは注意。
mapを2回使う
reduceRightじゃなくてmapで配列を反転。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
// 逆にする
const reversedArr = arr.map((_, i, a) => a[a.length - 1 - i])
<ul>
{
reversedArr.map((e, i) =>
<li key={i}>{e}</li>
)
}
</ul>
}
これもかなり良い。ちなみにmapを頑張って1回に縮めることもできる。こう。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
<ul>
{
arr.map((_, i, a) => (
<li key={i}>
{a[a.length - 1 - i]}
</li>
))
}
</ul>
}
スプレッド構文を使う
スプレッドで配列をばらした後もう一度まとめるだけ。reverseはその後普通に使う。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
// 逆にする
const reversedArr = [...arr].reverse()
<ul>
{
reversedArr.map((e, i) =>
<li key={i}>{e}</li>
)
}
</ul>
}
最強。めっちゃ良い。一度描画したら順番が変わらない配列はこれで良いと思う。 速度?わからん
CSSのorderを使う
でも、配列が逆になったりまた戻ったりまた逆になったりする配列は↑のmapとかスプレッドとか使えない。↑の使うと逆になった後にまた戻すとかは面倒です。そういう時に使えるのがCSSのorder使う方法。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
<ul style={{ display: 'flex' }}>
{
arr.map((e, i) =>
<li key={i} style={{order: -i}}>
{e}
</li>
)
}
</ul>
}
配列自体はそのまま出力するけど、flex orderを負の値にすることで逆向きに描画していく方法です。mapのやつとどっちが早いかはわかんないけど、自由度はこっちが上。例えば状態によって逆にするかしないかとかもできます。こう。
const foo = () => {
const arr = ['さいしょ', 'つぎ', 'さいご']
// 反転するかしないか
const isReversed = true
<ul style={{ display: 'flex' }}>
{
arr.map((e, i) =>
<li key={i} style={{
order:isReversed ? -i : i
}}>
{e}
</li>
)
}
</ul>
}
って考えるとこの方法が最強な気がする。
最後に
静的な配列はスプレッド、動的な配列はflexorderがいいかなというのが所感です。配列を逆にすることは結構あるので(たぶん)、ぜひとも参考にしてね!
(reverseが非破壊になればこんなことする必要もないんだけどね。非破壊にならないかなー)