【React】JavaScriptのSetを使って配列の重複削除して、ユニークな値だけを抽出する方法
Reactに限った話ではありませんが、ネイティブのJavaScriptのSetを使って配列の重複削除して、ユニークな値だけを取り出す方法を紹介します。
配列の中にオブジェクトがあり、そのカテゴリー名でフィルダーしたい場合を例に紹介します。
そもそもSetとは何かについては、以下の記事を参考にしてみてください。
JavaScriptのSetを使って配列の重複削除して、ユニークな値だけを取り出す方法
たとえば、以下のようなデータから、categoryの値を一意のユニークな値のみの配列にしたいとします。
const data = [
{
id: 1,
category: 'カテゴリ1',
image: Image9,
title: "タイトル1",
},
{
id: 2,
category: 'カテゴリ1',
image: Image9,
title: "タイトル2",
},
{
id: 3,
category: 'カテゴリ2',
image: Image9,
title: "タイトル3",
},
{
id: 4,
category: 'カテゴリ2',
image: Image9,
title: "タイトル4",
},
{
id: 5,
category: 'カテゴリ3',
image: Image9,
title: "タイトル5",
},
{
id: 6,
category: 'カテゴリ4',
image: Image9,
title: "タイトル6",
},
]
その場合、Setを使えば以下のように簡単にしかも簡潔に重複したデータを削除して、カテゴリー一覧を抽出することが可能です。
const categories = data.map(item => item.category);
const uniqueCategories = new Set(categories);
// Set(4) {'カテゴリ1', 'カテゴリ2', 'カテゴリ3', 'カテゴリ4'}
重複削除したユニークなデータに新しい値を追加したい場合
たとえば、カテゴリー一覧に"all"などを付け足したい場合があります。
その場合、Setは分割代入で配列に戻すことができるので、以下のように記述します。
const uniqueCategories = ["all", ...new Set(categories)];
console.log(uniqueCategories);
// (5) ['all', 'カテゴリ1', 'カテゴリ2', 'カテゴリ3', 'カテゴリ4']
重複削除したユニークな値のみを抽出する方法は、他にもいくつかありますが、
Setを使うと最もシンプルなコードになります。
Reactでカテゴリーをフィルターしたデータを表示したい場合
import { useState } from "react";
import data from "./data";
import ProjectCategories from "./ProjectCategories";
import Projects from "./Projects";
const Sample = () => {
const [projects, setProjects] = useState(data);
const categories = data.map((item) => item.category);
const uniqueCategories = ["all", ...new Set(categories)];
const filterProjectHandler = (category) => {
if (category === "all") {
setProjects(data);
return;
}
const filterProjects = data.filter(
(project) => project.category === category
);
setProjects(filterProjects);
};
return (
<section>
<div className="container">
<ProjectCategories categories={uniqueCategories} onFilterProjects={filterProjectHandler} />
<Projects projects={projects} />
</div>
</section>
);
};
export default Sample;
重複削除したユニークな値のみのカテゴリーデータにしてから、
上のような感じでfilterでそのカテゴリーとデータのカテゴリで一致するものを取得します。
それを更新用関数にセットしてあげることでデータが更新できます。
上のケースの"all"の場合などすべてを表示したいとき、更新用関数に全データをセットしてあげることで初期状態と同じにすることができます。
ProjectCategories(フィルダーする子コンポーネント)
import React, { useState } from "react";
const ProjectCategories = ({ categories, onFilterProjects }) => {
const [activeCategory, setActiveCategory] = useState("all");
const changeCategoryHandler = (activeCat) => {
setActiveCategory(activeCat); // カテゴリーをセット
onFilterProjects(activeCat); // そのカテゴリーでフィルター
};
return (
<div className="portfolio__categories">
{categories.map((category) => (
<button key={category} className={`btn cat__btn ${
activeCategory === category ? "primary" : "white"
} `}
onClick={() => changeCategoryHandler(category)}>{category}</button>
))}
</div>
);
};
export default ProjectCategories;
あとは、実際にフィルダーする子コンポーネントで、ボタンを作って、そのボタンにonClickをセットします。
セットする処理内容は、ボタンがクリックされたら
カテゴリーをそのボタンのカテゴリーにセットすることと
そのカテゴリーでカードをフィルターすること
の2点あります。
どちらもクリックしたカテゴリーが引数に必要なので、useStateで状態を作ってあげて、
それをクリックされたカテゴリー(activeCategory)の更新用関数にセットします。
そして、propsで渡ってきたフィルターの関数にクリックされたカテゴリーの情報を引数として渡してあげればフィルター機能が完成です。
クリックされたカテゴリーだけ見た目を変える
className={`btn cat__btn ${
activeCategory === category ? "primary" : "white"
} `}
クリックされたカテゴリーだけ見た目を変える場合、クリックされたカテゴリー(activeCategory)を条件分岐に利用して動的にcssのクラスを付与してあげればOKです。