我一直在开发一个需要获取大量数据并提供多种方法来过滤/搜索数据的项目,考虑到我将使用分页,我想在服务器端保留过滤。
我最近开始使用 React Context 并尝试了一种不起作用的方法。
这是我用来获取数据的自定义 React 钩子
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;
这是 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>
)
}
这是我尝试使用主页中的过滤选项的方法:
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>
// .....
现在我对此有两个问题:
houses
触发时,updateSearchParams
列表没有更新?我相信您在这里遇到的问题是由没有触发重新渲染引起的,因此您没有看到房屋有任何变化。
我认为解决此问题的最简单方法如下:
const [testParams, setTestParams] = useState(new URLSearchParams({ ... rest of the tings })
然后更新 updateSearchParams 以执行以下操作,而不是您正在执行的 testParams 设置:
setTestParams(prev => {
const new = new URLSearchParams(prev);
new.set(key, value);
return new;
});
此更改现在应该会导致 React 触发重新渲染,并希望向您展示更新后的房屋。
我也会小心您当前正在执行的 onChange,这可能会导致一些问题并发送大量请求。