reactjssearchmern

How can I save the search name and filters in react?


I have a site made using the MERN stack, and right now I am trying to save the search names and filters when the user clicks to return to the Families.jsx page.

GIF showing the problem.

Before, the search was done on the backend, but I changed it to do the search on the frontend, but I didn't think about this, and now I am kinda stuck not knowing where to start.

Families.jsx:

import { useEffect, useState, useContext, useMemo } from "react";
import axios from "axios";
import FamilySearchbar from "../../components/family/FamilySearchbar";
import FamilyCard from "../../components/family/FamilyCard";
import FamilyList from "../../components/family/FamilyList";
import Cookies from "js-cookie";
import { ViewContext } from "../../context/viewContext";

const normalize = (str) =>
  str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();

const Families = () => {
  const [families, setFamilies] = useState([]);
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedTags, setSelectedTags] = useState([]);
  const view = useContext(ViewContext);

  useEffect(() => {
    axios
      .get(`${import.meta.env.VITE_BASE_URL}/api/families/`, {
        headers: {
          Authorization: `Bearer ${Cookies.get("token")}`,
        },
      })
      .then((response) => {
        setFamilies(response.data);
      })
      .catch((error) => {
        console.error(error.response?.data?.message || error.message);
      });
  }, []);

  // Monta as opções únicas de tags dos produtos
  const tagOptions = useMemo(() => {
    const tagsSet = new Set();
    families.forEach(family =>
      family.products.forEach(product =>
        (product.tags || []).forEach(tag => tagsSet.add(tag))
      )
    );
    return Array.from(tagsSet).sort().map(tag => ({ value: tag, label: tag }));
  }, [families]);

  // Filtra famílias por nome e tags selecionadas
  const filteredFamilies = families.filter((family) =>
    family.products.some((product) => {
      if (!product.name) return false;
      const normalizedProductName = normalize(product.name);

      const matchesName = searchTerm
        .split(" ")
        .filter(Boolean)
        .every((term) => normalizedProductName.includes(normalize(term)));

      const matchesTags =
        selectedTags.length === 0 ||
        selectedTags.every((tag) =>
          (product.tags || []).includes(tag.value)
        );

      return matchesName && matchesTags;
    })
  );

  return (
    <div className="py-2 bg-light">
      <div className="container">
        <div>
          <FamilySearchbar
            searchTerm={searchTerm}
            setSearchTerm={setSearchTerm}
            tagOptions={tagOptions}
            selectedTags={selectedTags}
            setSelectedTags={setSelectedTags}
          />
        </div>
        {view.view === "card" ? (
          <div className="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
            {filteredFamilies
              .sort((a, b) => a.name.localeCompare(b.name))
              .map((family) => (
                <FamilyCard key={family._id} family={family} />
              ))}
          </div>
        ) : (
          <div className="row m-0 p-0">
            {filteredFamilies
              .sort((a, b) => a.name.localeCompare(b.name))
              .map((family) => (
                <FamilyList key={family._id} family={family} />
              ))}
          </div>
        )}
      </div>
    </div>
  );
};

export default Families;

BackButton.jsx:

import { useNavigate } from "react-router-dom";

const BackButton = () => {
  const navigate = useNavigate();

  const goBack = () => {
    navigate(-1);
  };

  return (
    <button type="button" className="btn btn-sm btn-qorange mb-1 mt-1 ms-1 float-end" onClick={goBack}>
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-return-left" viewBox="0 0 16 16">
        <path
          fillRule="evenodd"
          d="M14.5 1.5a.5.5 0 0 1 .5.5v4.8a2.5 2.5 0 0 1-2.5 2.5H2.707l3.347 3.346a.5.5 0 0 1-.708.708l-4.2-4.2a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 8.3H12.5A1.5 1.5 0 0 0 14 6.8V2a.5.5 0 0 1 .5-.5"
        />
      </svg>
    </button>
  );
};

export default BackButton;

I want the search name and filters to stay when the user clicks to return to the Families.jsx page. Any ideas on how I can achieve this?


Solution

  • To keep search filters saved when moving between pages in a React app, you can use React Context.

    React Context is useful when you want to share the search filters between different pages or components. You create a context and store your search values there. Since context is global, the values stay saved even if you navigate to another page and come back. Use React Context for better structure in bigger apps.