I have 6 articles and would like to know how can I filter the articles based on the article category. Currently, I have this nested categories array inside the articles array.
Now I have some static buttons for the categories, but onClick I need them to filter the existing array of articles.
import { NextPage } from "next";
import Head from "next/head";
import PreFooterModule from "@modules/PreFooterModule";
import Footer from "@components/Footer";
import ArticlesHero from "@components/ArticlesHero";
import Link from "next/link";
import { useState } from "react";
const Articles: NextPage = () => {
const [articles, setArticles] = useState([
{
image: "https://picsum.photos/1280/720?=1",
title: "Article #1",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Fashion", "Products"],
},
{
image: "https://picsum.photos/1280/720?=2",
title: "Article #2",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Fashion", "Travel"],
},
{
image: "https://picsum.photos/1280/720?=3",
title: "Article #3",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Movies", "Studio"],
},
{
image: "https://picsum.photos/1280/720?=4",
title: "Article #4",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Fashion", "Products"],
},
{
image: "https://picsum.photos/1280/720?=5",
title: "Article #5",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Television", "Movies"],
},
{
image: "https://picsum.photos/1280/720?=6",
title: "Article #6",
text: "Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.",
categories: ["Studio", "Fashion"],
},
]);
return (
<>
<Head>
<title>Artikel Overzicht</title>
<meta name="author" content="" />
<meta name="description" content="" />
<link rel="icon" href="/favicon.ico" />
</Head>
<ArticlesHero
title="Artikel Overzicht"
text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
/>
<div className="max-w-screen-xl px-6 pt-16 pb-12 mx-auto lg:px-8 text-navyBlue">
<div className="flex gap-2 py-7">
<a href="#" className="badge badge-primary">
Fashion
</a>
<a href="#" className="badge badge-primary">
Studio
</a>
<a href="#" className="badge badge-primary">
Movies
</a>
<a href="#" className="badge badge-primary">
Products
</a>
<a href="#" className="badge badge-primary">
Travel
</a>
<a href="#" className="badge badge-primary">
Television
</a>
</div>
<div className="grid grid-cols-1 gap-y-10 gap-x-4 md:grid-cols-12">
{articles.map(({ image, title, text, categories }) => (
<article className="col-span-6 lg:col-span-4">
<img
className="object-cover rounded-md aspect-video"
src={image}
alt=""
/>
<div className="pt-4">
<div className="card-actions">
{categories.map((category) => (
<Link href="/tag/fashion" passHref>
<span className="text-[11px] font-semibold uppercase cursor-pointer badge badge-outline hover:bg-navyBlue hover:text-white">
{category}
</span>
</Link>
))}
</div>
</div>
<div className="py-3">
<h5 className="mb-2 text-2xl font-medium tracking-tight text-navyBlue md:text-3xl">
{title}
</h5>
<p className="text-sm leading-snug text-black md:text-normal">
{text}
</p>
<Link href="/article/first-article" passHref>
<span className="inline-flex items-center justify-center px-4 py-1.5 md:py-2 text-xs font-medium uppercase transition duration-150 ease-in-out bg-transparent border rounded-full shadow-sm cursor-pointer mt-5 text-navyBlue border-navyBlue place-self-start hover:border-transparent hover:bg-navyBlue hover:text-white">
Read more
<svg
className="w-4 h-4 ml-2 -mr-1"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
</span>
</Link>
</div>
</article>
))}
</div>
</div>
<PreFooterModule />
<Footer />
</>
);
};
export default Articles;
>Solution :
First you need to clone the state. There need to be a copy of the articles. So that if we filter and set the state we won’t lose other articles. So do something like,
const [articlesCopy, setArticlesCopy] = useState(articles)
Then, on clicking each buttons you should fire a function with the category as parameter. And this function is responsible of filtering the data present in articlesCopy and sets in articles state.
So create a function like,
const filterByCategory = (category) => {
const filteredArticles = articles.filter(article => article.categories.includes(category); // Filter based on category
setArticles(filteredArticles); // Set the actual state, so it re-renders
}
And in your button do something like,
<a onClick={()=>filterByCategory("Fashion")} className="badge badge-primary">
Fashion
</a>
<a onClick={()=>filterByCategory("Movies")} className="badge badge-primary">
Movies
</a>
....
First you need to clone the state. There need to be a copy of the articles. So that if we filter and set the state we won’t lose other articles. So do something like,
const [articlesCopy, setArticlesCopy] = useState(articles)
Then, on clicking each buttons you should fire a function with the category as parameter. And this function is responsible of filtering the data present in articlesCopy and sets in articles state.
So create a function like,
const filterByCategory = (category) => {
const filteredArticles = articles.filter(article => article.categories.includes(category); // Filter based on category
setArticles(filteredArticles); // Set the actual state, so it re-renders
}
And in your button do something like,
<a onClick={()=>filterByCategory("Fashion")} className="badge badge-primary">
Fashion
</a>
<a onClick={()=>filterByCategory("Movies")} className="badge badge-primary">
Movies
</a>
....
To render those buttons dynamically you can do something like,
let categories = [];
articles.forEach(article => {
categories.push(article.categories);
});
categories = Array.from(new Set(categories));
setCategories(categories);
And use this new categories state to render those buttons