filter・map関数の便利さは異常
reactを学んだときにまず出てくる、map関数、ループ処理くらいの認識ですぐに使ってしまいがちです。
さらに、filter関数。条件付きで配列を扱えるmapの仲間みたいな認識で学びました。
const products = [
{ id: 1, name: "Laptop", stock: 5 },
{ id: 2, name: "Keyboard", stock: 0 },
{ id: 3, name: "Mouse", stock: 10 },
{ id: 4, name: "Monitor", stock: 0 },
{ id: 5, name: "Headphones", stock: 3 },
];
例えば、上記のような在庫管理テーブルがあったとします。
これらのデータのうち、在庫がある商品の名前を取得するとします。
const availableProducts = products
.filter((product) => product.stock > 0) // 在庫がある商品を抽出
.map((product) => product.name); // 商品名だけを取り出す
console.log(availableProducts);
// 結果: ["Laptop", "Mouse", "Headphones"]
react初学者の自分はまず最初に上記のような書き方を考えつきました。
このようなシンプルな処理の場合はこちらの書き方で問題はありません。
なんでもfilter・mapするんじゃない
しかしmap関数、filter関数を同時に扱う時に、気をつけなければいけないことがあります。
上記の処理では、filter関数で一度配列全体を走査した結果に対してmap関数はもう一度配列を走査しています。
配列のデータ数が膨大、または条件が複雑になった時、パフォーマンスの低下を招きかねません。
そこで使いたいのがreduceです。
reduceとは?
reduceは配列の各要素を1つづつ処理して、最終的に1つの結果を作り出すためのメソッドです。
シンプルな例だと以下のような使い方をします。配列内の数値の合計を計算しています。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((total, current) => total + current, 0);
console.log(sum); // 結果: 15
redueの第一引数は累積値、第二引数は現在の値を意味します。
mapやfilterと異なり、配列を扱う時の汎用性が高いです。
先ほどの在庫管理の例をreduceで書いてみましょう。
const { availableProducts, outOfStockProducts } = products.reduce(
(result, product) => {
if (product.stock > 0) {
result.availableProducts.push(product.name); // 在庫ありの商品名を追加
} else {
result.outOfStockProducts.push(product.name); // 在庫切れの商品名を追加
}
return result;
},
{ availableProducts: [], outOfStockProducts: [] } // 初期値
);
console.log(availableProducts);
// 結果: ["Laptop", "Mouse", "Headphones"]
console.log(outOfStockProducts);
// 結果: ["Keyboard", "Monitor"]
一回の配列の走査で在庫がある商品と在庫がないの商品のリストを作成できました。
まとめ
reduceを使うことでコードの見やすさは落ちます。(filter・mapは誰が見ても何やってるか見やすい)
しかし、膨大なデータ・複雑な条件で配列を加工したい場合は、reduceを検討してみてください。