Reactを使って開発をする場合は、JSXという構文を用いる場合がほとんどだと思います。
JSXで書かれたプログラムを見ていると、以下のような書き方を目にすることがあるかも知れません。
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<ul>
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
);
}
}
配列のmapメソッドが用いられていますね。
上記のReactコンポーネントは、ブラウザ上では以下のように表示されます。
配列の中身が、一覧表示されています。
こちらの記事では、上記のように、mapメソッドを用いてJavaScriptの配列の中身を描画する方法と、その注意点について記載していきたいと思います。
(実際に手元でソースコードを動かしながら見ていきたい人は、この記事の最下部に、動かせるサンプルコードがあるので、そちらをローカルPCに取得して、動かしてみてください。)
動画での説明
このブログの内容は、以下の動画でも一通り説明しています。
動画の方が理解しやすい方は、こちらの動画をご覧になってからこの記事を読まれると、分かりやすいかもしれません。
なぜReactでは配列のmapメソッドを用いるか
なぜReactで配列の中身を一覧表示するときに、mapメソッドが用いられるのでしょうか。
理由は以下の2点です。
- {}内に記述した配列の要素が並べて表示されるから
- mapメソッドが、戻り値として新しい配列を返すから
ひとつずつ見ていきましょう。
{}内に記述した配列の要素が並べて表示される
たとえば、以下のようなコンポーネントを見てみましょう。
class App extends React.Component {
render() {
const arr = [<li>リンゴ</li>, <li>パイナップル</li>, <li>ペン</li>];
return (
<ul>
{arr}
</ul>
);
}
}
ブラウザ上に表示してみると、以下のようになります。
表示結果は、さっきと一緒ですね。
ソースコードで何をやっているのかを見てみると、
const arr = [<li>リンゴ</li>, <li>パイナップル</li>, <li>ペン</li>];
の部分では、配列内に、JSXの<li>要素を、配列に突っ込んでいることが分かります。
このarrという配列を、
<ul>
{arr}
</ul>
の部分で、{}内に、そのまま記載しています。
Reactでは、配列内にJSXの要素を入れて、その配列を{}内に記載するだけで、一覧表示ができるのです。
余談になりますが、ReactではなくVueを用いた場合は、v-forなどのVue独自の構文を覚えて使うことになると思います。
Reactの素晴らしいところは、そういった新しい構文を覚える必要が一切なく、あくまでも全てJavaScriptの世界の中で実現できてしまうことだと思います…
少し話が逸れましたが、Reactでは、
JSXの要素を含んだ配列を{}で囲むだけで、一覧表示ができる
という点を覚えておいて頂けたらと思います。
mapメソッドは、戻り値として新しい配列を返す
上記のような方法を使えば、Reactで一覧表示ができることが分かりました。
しかし、配列を以下のように宣言しなければいけないのは、少し面倒です。
const arr = [<li>リンゴ</li>, <li>パイナップル</li>, <li>ペン</li>];
何が面倒なのかと言うと、いちいち全ての要素を、<li>タグで括る必要があるからです。
今回は配列要素をソースにべた書きしているので、一つずつ地道に<li>タグで括ることができましたが、
たとえば
要素が1000個あるような配列の場合はどうするのでしょうか
もしくは、
JavaScriptを実行するまでは、いくつの要素が配列に格納されるか分からないような場合はどうするのでしょうか。
そこで登場するのが、JavaScriptのmapというメソッドです。
このmapというメソッドは、特にReact独自の構文などではなく、あくまでも、JavaScriptの配列のメソッドです:
MDN web docs | Array.prototype.map() >>
このmapというメソッドは、
配列内のそれぞれの要素用いて、新しい配列を作る
ことができます。
上記のサイトの例をそのまま拝借すると、以下のような感じです。
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
上記のプログラムでは、
[1, 4, 9, 16]
という配列を元にして、それぞれの要素の数字を2倍した
[2, 8, 18, 32]
という、新しい配列を生成しています。
ミソとしては、元の配列そのものを変更しているわけではなく、
要素の数字を2倍した新しい配列が、戻り値として返される点です。
上述の例では、mapメソッドを用いて「それぞれの要素の数字を2倍する」という操作をしていますが、
この記事で実現したいこととしては、「それぞれの要素を<li>タグで括る」という操作になります。
それを踏まえて、この記事の一番最初に見た例を、もう一度見てみましょう:
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<ul>
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
);
}
}
上記のプログラムの「key={i}」という記述については後述しますが、
それ以外の部分は大体わかって頂けるかと思います。
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
と記述することによって、配列に文字列として格納されている各要素を、<li>タグで括った、新しい配列を作っているのです。
その新しい配列が{}内に記載されていることによって、一覧として表示されるような仕組みです。
配列の一覧表示時の”key”について
こちらは、Reactのルールとして覚えておいて頂ければと思うのですが、
上述のkeyを記載しないと、開発環境では以下のようなエラーが表示されます。
実は、React上で{}内の配列を一覧表示する際には、keyという属性を付与することが義務付けられています。
これは、配列の要素が動的に変更された時に、変更前の配列の要素との対応関係をReact側が認識するためです… が、細かいことは気にせず、
{}を用いて配列の要素を展開する時は、keyを付ける必要があるのだ
と、覚えておけば良いと思います。
今回の例では以下のように、<li>要素の属性として、keyを付与していましたね。
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
この、
key={i}
の「i」は、配列要素のインデクス番号です。
mapメソッドの第二引数には、各配列要素のインデクス番号が渡されてくるので、それをそのままkeyとして流用しています。
一意であれば何でも良いのですが、インデクス番号であれば、各要素で一意であることが保証されているので、使いやすいと思います。
(インデクス番号をkeyとして使って困るパターンに関しては、この記事上部の動画で説明しているので、気になる方は、動画の方もご参照ください。)
メソッドチェーンを用いた一覧のカスタマイズ
さて、上記の内容が分かれば、いろいろな応用が可能です。
上記のmapはReact固有の構文などではなく、ただのJavaScriptの配列のメソッドですから、JavaScriptのその他のメソッドと組み合わせることができます。
たとえば、以下のようなことが可能です。
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<ul>
{arr.filter(fruit => fruit.includes("ル")).map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
);
}
}
上記のソースコードでは、JavaScriptの配列のfilterメソッドを用いて、「ル」という文字を含む要素だけの配列を生成しています。
プログラムの実行結果は、以下のようになります。
パイナップルだけが表示されていますね。
以下のように記述すれば、一覧の並び替えも可能です。
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<ul>
{arr.sort().map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
);
}
}
上記では、JavaScriptの配列のsortメソッドを用いて、配列要素を辞書順に並び替えています。
実行結果は以下のようになります。
並び替えられた結果が表示されていることが分かります。
(JavaScriptのsortメソッドは、引数なしの場合はUnicodeに変換した値での辞書順のソートを行う)
配列のメソッドチェーンで一覧を表示する際の注意点
さて、上記のような方法を用いれば、React上で配列の要素を展開して表示できることが分かりました。
しかし、1点注意しないといけないと思うことがあるので、記載しておきます。
それは、上記のような記述を行う場合は、
配列メソッドが、元の配列に影響を与えないか
ということを気にした方が良いという点です。
たとえば、以下のプログラムを見てみます。
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<div>
ソートした一覧
<ul>
{arr.sort().map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
ソートしてない一覧
<ul>
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
</div>
);
}
}
上記のプログラムでは、同じ配列を用いて、
「ソートした一覧」と「ソートしてない一覧」という、2つの一覧を表示しています。
上記のプログラムの結果は、どのように表示されるでしょうか。
よかったら、ちょっと考えてみてください。
結果は、以下のようになります。
どうでしょう。
予想通りでしょうか?
結果としては、両方ソートされてしまっています。
なぜこのような結果になるのかと言うと、JavaScriptの配列のsortというメソッドが、「元の配列を直接いじる」ようなメソッドだからです。
つまり、1つ目の一覧を表示する時にsortが行われたことによって、元の配列自体の並び順が変わってしまい、後続の処理でその配列を使う時点で、並び順が変わってしまっていたということになります。
Reactで配列を展開して一覧表示する際は、「元の配列に変更を加えてしまっていないか」という点は、気にかけながらソースを書いていく必要があるかと思います。
まとめ
如何でしたでしょうか。
「全てがJavaScriptで記述できる」というのは、Reactの素晴らしい点です。
mapというJavaScriptのメソッドを用いるだけでなく、JavaScriptに元々備わっている多様な機能をフル活用して、柔軟なプログラミングをすることができます。
その一方で、JavaScriptの理解が浅いと、思わぬ落とし穴にハマってしまうかも知れません。。。
本記事が、ReactやJavaScriptを学習中の方々の参考になれば幸いです。
ソースコードサンプル
<!DOCTYPE html>
<html>
<head>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
render() {
const arr = ["リンゴ", "パイナップル", "ペン"];
return (
<ul>
{arr.map((fruit, i) => <li key={i}>{fruit}</li>)}
</ul>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>
</body>
</html>
コメント
Reactの公式リファレンスには時々怒りを覚えますね!サンプルが無説明すぎるだろFacebook!
「リストとkey」の説明においても、mapは一意のKeyを指定しなきゃエラー出るよーまでは分かります。でも解説用サンプルにいきなりkey={○○.toString()}とか説明なしで使用しちゃうもんですから意味不明で困った困った。。。
しかも「深く考えなくても.id使っとけば間違いないよ」と一言そえて。それなら始めから使うな!
たぶん
1、keyをindexで管理すると楽そうね(と思った人向け)
2、でも配列だから固定とは限らないじゃない。最悪エラーでちゃうわ
3、それなら数字を文字列に変換しときましょtoSt(ベストの方法じゃないけど最低限やっとけよ)
って意味なんでしょうけど、過程を一切書いてくれないから考えすぎて頭もげるかと思いましたわ。初心者にはキツイ。すみません愚痴でした、長々すみません。
ちなみにあのチュートリアルはFacebookじゃなくて有志の方々が無報酬で作ってるんですってね。。。アメリカさんは懐が深いや
コメントありがとうございます!
そうですね、Reactの公式リファレンスはあまり初心者の方向けには作られていない気がしますよね…(^^;)
「JavaScriptの文法が曖昧な人は、別のサイトで復習してきてね!」って言い放っちゃってますもんね…笑
僕も仕事でしばらくReact使っていてやっと慣れてきましたが、最初は完全に意味不明でした笑