1

I am currently building an e-commerce website with React, and I have question about query params.

In every e-commerce website, there are filters. I want to use useSearchParams for this filter (sort, conditions, min price, max price, categories, etc.). But I am not 100% sure if I am using searchParams correctly.

I am currently using react state for conditions and sort, and update searchParams using useEffect.

Code:

export default function Shop() {
  const [searchParams, setSearchParams] = useSearchParams();
  const [sort, setSort] = useState("newest");
  const [conditions, setConditions] = useState([]);

  const handleChangeSort = (e) => {
    setSort(e.target.value);
    searchParams.set("sort", sort);
    setSearchParams(searchParams);
  };

  const handleChangeConditions = (e, checked, newValue) => {
    if (checked) {
      const newList = [...conditions, newValue];
      setConditions(newList);
      return;
    }

    const newList = conditions.filter((condition) => condition !== newValue);
    setConditions(newList);
  };

  const handleReset = () => {
    setSort("newest");
    setConditions([]);
  };

  useEffect(() => {
    if (conditions.length === 0) {
      searchParams.delete("conditions");
      setSearchParams(searchParams);
      return;
    }

    searchParams.set("conditions", JSON.stringify(conditions));
    setSearchParams(searchParams);
  }, [conditions, searchParams, setSearchParams]);

  return (
    <>
      <Sort sort={sort} onChange={handleChangeSort} />
      <Conditions conditions={conditions} onChange={handleChangeConditions} />
      <Button variant="contained" onClick={handleReset}>
        Reset Filter
      </Button>
    </>
  );
}

Link to CodeSandbox

Is this right approach? Or am I doing something wrong?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181

1 Answers1

0

The "right" approach is the one that works for your use case. I don't see any overt issues with the way you are using the queryString parameters. Here I'd say if you want the React state to be the source of truth and the queryString as the cached version then you'll want to initialize the state from the query params and persist the state updates to the query params. This keeps the query params and local component state synchronized.

Example:

export default function Shop() {
  const [searchParams, setSearchParams] = useSearchParams();

  // Initialize states from query params, provide fallback initial values
  const [sort, setSort] = useState(searchParams.get("sort") || "newest");
  const [conditions, setConditions] = useState(
    JSON.parse(searchParams.get("conditions")) || []
  );

  // Handle updating sort state
  const handleChangeSort = (e) => {
    setSort(e.target.value);
  };

  // Persist sort to query params
  useEffect(() => {
    searchParams.set("sort", sort);
    setSearchParams(searchParams);
  }, [searchParams, setSearchParams, sort]);

  // Handle updating conditions state
  const handleChangeConditions = (e, checked, newValue) => {
    if (checked) {
      setConditions((conditions) => conditions.concat(newValue));
    } else {
      setConditions((conditions) =>
        conditions.filter((condition) => condition !== newValue)
      );
    }
  };

  // Persist conditions to query params
  useEffect(() => {
    if (conditions.length) {
      searchParams.set("conditions", JSON.stringify(conditions));
    } else {
      searchParams.delete("conditions");
    }
    setSearchParams(searchParams);
  }, [conditions, searchParams, setSearchParams]);

  const handleReset = () => {
    setSort("newest");
    setConditions([]);
  };

  return (
    <>
      <Sort sort={sort} onChange={handleChangeSort} />
      <Conditions conditions={conditions} onChange={handleChangeConditions} />
      <Button variant="contained" onClick={handleReset}>
        Reset Filter
      </Button>
    </>
  );
}

Edit react-how-to-use-query-string-when-using-react-router-dom-v6

Drew Reese
  • 165,259
  • 14
  • 153
  • 181