skip to Main Content

I have created a simple search item page where

  1. On load, users will see all the items under their categories.
  2. Users will be able to search items.
  3. If found, items will be displayed or otherwise "No Items" will get displayed.

However, I still believe the code below is not optimized and can be shortened as I can see reluctant codes for every category mapping.

I’d appreciate to know how should I use one Filter and One mapping for the SECTION TO OPTIMIZE below. Thanks.

Code : https://codesandbox.io/s/beautiful-brahmagupta-79i9ih?file=/src/App.js

import React, { useEffect, useState } from "react";
import "./index.css";

const object = [
  { category: "One", name: "Mishanta" },
  { category: "One", name: "Virichia" },
  { category: "Two", name: "Steven" },
  { category: "Two", name: "Vikhostana" },
  { category: "Three", name: "Rockhosita" },
  { category: "Three", name: "Johnsonow" },
  { category: "Three", name: "Urvesta" },
  { category: "Two", name: "Dipuota" },
  { category: "One", name: "Dikhosta" }
];
const App = () => {
  const [searchedInput, setSearchedInput] = useState("");
  const [searchedItem, setSearchedItem] = useState([]);
  const [items, setItems] = useState([]);

  useEffect(() => {
    setItems(object);
  }, []);

  useEffect(() => {
    if (searchedInput !== "") {
      const arr = JSON.parse(JSON.stringify(object));
      const filteredData = arr.filter((value) => {
        const searchStr = searchedInput.replace(/s/g, "").toLowerCase();
        const nameMatches = value.name.toLowerCase().includes(searchStr);
        return nameMatches;
      });
      setSearchedItem(filteredData);
    }
  }, [searchedInput]);

  return (
    <>
      <input type="text" onChange={(e) => setSearchedInput(e.target.value)} />

      {searchedInput.length > 0 ? (
        searchedItem.length == 0 ? (
          <h4>No item found. Sorry bro..</h4>
        ) : (
          searchedItem.map((x, i) => (
            <>
              <h4>Category: {x.category}</h4>
              <span key={i} className="selected-styles">
                {x.name}
              </span>
            </>
          ))
        )
      ) : (
        <>
          // SECTION TO OPTIMIZE
          <h4>Category: One</h4>
          {items
            .filter((item) => item.category === "One")
            .map((x, i) => (
              <span key={i} className="styles">
                {x.name}
              </span>
            ))}

          <hr />

          <h4>Category: Two</h4>
          {items
            .filter((item) => item.category === "Two")
            .map((x, i) => (
              <span key={i} className="styles">
                {x.name}
              </span>
            ))}

          <hr />

          <h4>Category: Three</h4>
          {items
            .filter((item) => item.category === "Three")
            .map((x, i) => (
              <span key={i} className="styles">
                {x.name}
              </span>
            ))}
        </>
      )}
    </>
  );
};

export default App;


2

Answers


  1. you could extract the common filter to a separate functional component as the logic is the same for all the cases.

    you can write a common functional Component like the one below and pass the filter condition as a parameter.

    const ItemsFilter = ({ items, type }) => {
     return (
      <>
      {items
        .filter((item) => item.category === type)
        .map((x, i) => (
          <span key={i} className="styles">
            {x.name}
          </span>
        ))}
      </>
     );
    };
    

    then replace the duplicated filters and add ItemsFilter components in their place.

    <ItemsFilter items={items} type={"One"} />
    

    modified codesandbox link

    Login or Signup to reply.
  2. you could group the objects if that works, say if its always based off that property. So you can start with some function that takes an array of objects and groups them into an object of arrays, or here I used map as its probably more suited.

    const groupBy = (arr, key) =>
      arr.reduce(
        (pre, curr) =>
          new Map(pre.set(curr[key], [...(pre.get(curr[key]) || []), curr])),
        new Map()
      );
    

    Then for the JSX part you can call the function

          {[...groupBy(items, "category").entries()].map(
            ([category, items]) => (
              <>
                <h4>Category: {category}</h4>
                {items.map((item) => (
                  <span key={item} className="styles">
                    {item.name}
                  </span>
                ))}
                <hr />
              </>
            )
          )}
    

    It’s a bit less code and works for any category. Eventually if you wanted more flexibility in terms of the grouping you can replace key arg with a function that should return the group given the item, but looking at the data you have this seems a good start.

    https://codesandbox.io/s/dazzling-swanson-81wufo?file=/src/App.js

    Best

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search