How can I filter and render data according to category selected?

Viewed 579

I am new to React. I am trying to filter and render products according to selected category. I don't know where to start? Any help is appreciated.

Also why is event value and filterBy value different ( Check console and click on different categories ). Shouldn't they be same?

List.js

import React, { Fragment, useState } from "react";
import "./List.css";
import ListItem from "./ListItem";
import Dropdown from "./Dropdown";
import { DUMMY_EXPENSES } from "../Data.js";

function List() {
  const [data, setData] = useState(DUMMY_EXPENSES);
  const [filterBy, setFilterBy] = useState({});

  const tags = data.map((tagItem) => {
    return tagItem.tag;
  });

  const changeHandler = (e) => {
    console.log('event value :', e.target.value);
    setFilterBy(() => ({category : e.target.value}))
    console.log(filterBy)
  };

  const uniqueCategory = [...new Set(tags)];
  const products = data.map((item) => (
    <ListItem
      key={item.id}
      id={item.id}
      title={item.title}
      amount={item.amount}
      date={item.date}
      tag={item.tag}
    />
  ));

  return (
    <Fragment>
      <div className="header">
        <h1>Filter</h1>
      </div>
      <Dropdown
        uniqueCategory={uniqueCategory}
        changeHandler={changeHandler}
      />
      <div className="card-container">{products}</div>
    </Fragment>
  );
}

export default List;

Dropdown.js

import React, { Fragment } from "react";
import "./Dropdown.css";

function Dropdown(props) {
  const { changeHandler, uniqueCategory } = props;
  return (
    <Fragment>
      <div className="dropdown">
        <label htmlFor="tag">Sort by: </label>
        <select name="tag" id="tag" onChange={changeHandler}>
          <option value="all">All</option>
          {uniqueCategory.map((item) => (
            <option value={item} key={item} >
              {item}
            </option>
          ))}
        </select>
      </div>
    </Fragment>
  );
}

export default Dropdown;

Data to filter. I am showing here only a part of it just to give you an idea.

export const DUMMY_EXPENSES = [
  {
    id: "e1",
    title: "Office Paper",
    amount: 94.12,
    date: new Date(2020, 7, 14),
    tag: "stationery",
    tagId: 1
  },
  {
    id: "e2",
    title: "New TV",
    amount: 799.49,
    date: new Date(2021, 2, 12),
    tag: "electronic",
    tagId:2
  },
]

enter image description here

1 Answers

setState is asynchronous, the second console.log is displaying the previous value because the new value has not been updated yet. If you put the console.log(filterBy) outside the changeHandler method you will see the correct value.

To filter the data you just need to apply the filter method and then display the filtered data.

const [filterBy, setFilterBy] = useState({ category: "all" });

let filteredProducts = data;

if (filterBy.category !== "all") {
  filteredProducts = filteredProducts.filter((product) => product.tag === filterBy.category);
}

const products = filteredProducts.map((item) => (
  <ListItem
    key={item.id}
    id={item.id}
    title={item.title}
    amount={item.amount}
    date={item.date}
    tag={item.tag}
  />
));
Related