I have been working on a project that requires fetching a bunch of data and provides multiple ways to filter/search the data, and I though about keeping filtering on the server-side considering I’ll be using pagination.
I started using React Context recently and tried an approach that didn’t work.
here’s the custom React hook I’m using to fetch data
import { useState, useEffect } from 'react';
const useFetch = (url, url_params) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [refresh, setRefresh] = useState(0);
if (url_params) {
url = url + '?' + url_params.toString();
}
const refreshData = () => {
setRefresh((prev) => prev + 1);
}
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [refresh, url]);
return { data, loading, error, refreshData };
};
export default useFetch;
and here is the contextProvider:
import { createContext, useState, useEffect, useContext } from "react";
import { listing_url } from "../../Hooks/api_endpoints";
import useFetch from "../../Hooks/useFetch";
import { useSearchParams } from "react-router-dom";
export const HouseContext = createContext();
export const HouseProvider = ({ children }) => {
const [selectedHouse, setSelectedHouse] = useState(null);
// I have tried multiple approaches for searchParams (one is search params and the other is testParams
const [searchParams, setSearchparams] = useState({
address__icontains: '',
apartment_no__icontains: '',
block__iexact: '',
currency__iexact: '',
floor__iexact: '',
gross__gte: '',
gross__lte: '',
net__gte: '',
net__lte: '',
num_of_floors__iexact: '',
num_of_rooms__iexact: '',
owner__icontains: '',
owner_phone_num__icontains: '',
price__gte: '',
price__lte: '',
status__iexact: '',
view__icontains: '',
});
// second attempt at implementing searchParams
const testParams = new URLSearchParams({
address__icontains: '',
apartment_no__icontains: '',
block__iexact: '',
currency__iexact: '',
floor__iexact: '',
gross__gte: '',
gross__lte: '',
net__gte: '',
net__lte: '',
num_of_floors__iexact: '',
num_of_rooms__iexact: '',
owner__icontains: '',
owner_phone_num__icontains: '',
price__gte: '',
price__lte: '',
status__iexact: '',
view__icontains: '',
});
const { data: houses, error: housesError, loading: housesLoading, refreshData: houseRefresh } = useFetch(listing_url, testParams);
const createHouse = async (house) => {
const newHouse = await fetch(listing_url, {
method: "POST",
body: JSON.stringify(houseData),
});
setHouses([...houses, newHouse]);
}
// useEffect(() => {
// console.log("houses were updated")
// console.log(' search params were updated')
// }, [houses, testParams])
const updateSearchParams = (key, value) => {
console.log("firing updateSearchParams")
houseRefresh();
testParams.set(key, value);
}
return (
<HouseContext.Provider value={{ houses, selectedHouse, housesError, housesLoading, setSelectedHouse, createHouse, testParams, updateSearchParams }}>
{children}
</HouseContext.Provider>
)
}
and here’s how I tried to use the filtering options in my Homepage:
import { HouseContext } from '../../Context/House/House';
// .....
export default function Home() {
// .....
const { testParams, updateSearchParams } = useContext(HouseContext)
// ......
return (
// ......
<div className='flex'>
<span className='text-sm/3 my-auto pr-2 dark:text-white'>floor</span>
<input type='number' placeholder='floor' min={0} onChange={(e) => { updateSearchParams('floor__iexact', e.target.value) }} className='w-14 rounded border border-black' />
</div>
// .....
now I have 2 questions about this:
- why is the
houses
list not getting updated whenupdateSearchParams
is firing? - is this approach valid or should I just resort to fetching the data and then filtering client-side? and if so, how will I do so once pagination is added?