带有 React-Query 的搜索框
Search box with React-Query
我正在尝试通过 text
实施产品搜索。使用 react-query
获取数据。以下实现正在运行,但我觉得不合适。让我知道我是否做得过头了,如果有更简单的解决方案 react-query
.
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useQueryClient } from 'react-query';
import ProductCard from '@/components/cards/ProductCard';
import { useQueryProducts } from '@/hooks/query/product';
import { selectSearch } from '@/store/search';
// function fetchProductsByFilter(text){}
const Shop = ({ count }) => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const { text } = useSelector(selectSearch);
const productsQuery = useQueryProducts(count);
useEffect(() => {
setProducts(productsQuery.data);
setLoading(false);
}, []);
const queryClient = useQueryClient();
useEffect(() => {
const delayed = setTimeout(() => {
queryClient.prefetchQuery(['searchProductsByText'], async () => {
if (text) {
const data = await fetchProductsByFilter(text);
setProducts(data);
setLoading(false);
return data;
}
});
}, 300);
return () => clearTimeout(delayed);
}, [text]);
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-3">search/filter menu</div>
<div className="col-md-9">
{loading ? (
<h4 className="text-danger">Loading...</h4>
) : (
<h4 className="text-danger">Products</h4>
)}
{products.length < 1 && <p>No products found</p>}
<div className="row pb-5">
{products.map((item) => (
<div key={item._id} className="col-md-4 mt-3">
<ProductCard product={item} />
</div>
))}
</div>
</div>
</div>
</div>
);
};
// async function getServerSideProps(context) {}
export default Shop;
我觉得这不是很地道。使用 react-query,使用过滤器的关键是将它们 放入 查询键中。由于每次键更改时 react-query 都会重新获取,因此每次更改过滤器时都会重新获取,这通常是您想要的。这是一种非常明确的做事方式。根本不需要useEffect。
如果在从 select 中选择某项或单击应用按钮时发生这种情况,这就是您真正需要的:
const [filter, setFilter] = React.useState(undefined)
const { data, isLoading } = useQuery(
['products', filter],
() => fetchProducts(filter)
{ enabled: Boolean(filter) }
)
在这里,只要过滤器是 undefined
,我就会另外禁用查询 - 一旦我们调用 setFilter
.
,抓取就会开始
如果涉及在文本字段中键入内容,我建议进行一些去抖动以避免触发过多请求。 useDebounce hook 对此非常有用。你仍然有 useState
,但你会使用查询的去抖动值:
const [filter, setFilter] = React.useState(undefined)
const debouncedFilter = useDebounce(filter, 500);
const { data, isLoading } = useQuery(
['products', debouncedFilter],
() => fetchProducts(debouncedFilter)
{ enabled: Boolean(debouncedFilter) }
)
如果在从 select 中选择某项或单击应用按钮时发生这种情况,这就是您真正需要的:
const [filter, setFilter] = useState<string>('')
const isEnabled = Boolean(filter)
const { data, isLoading } = useQuery(
['products', filter],
() => fetchProducts(filter)
{ enabled: enabled: filter ? isEnabled : !isEnabled, }
)
<input type="text" onChange={(e) => setFilter(e.target.value)}/>
我正在尝试通过 text
实施产品搜索。使用 react-query
获取数据。以下实现正在运行,但我觉得不合适。让我知道我是否做得过头了,如果有更简单的解决方案 react-query
.
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useQueryClient } from 'react-query';
import ProductCard from '@/components/cards/ProductCard';
import { useQueryProducts } from '@/hooks/query/product';
import { selectSearch } from '@/store/search';
// function fetchProductsByFilter(text){}
const Shop = ({ count }) => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const { text } = useSelector(selectSearch);
const productsQuery = useQueryProducts(count);
useEffect(() => {
setProducts(productsQuery.data);
setLoading(false);
}, []);
const queryClient = useQueryClient();
useEffect(() => {
const delayed = setTimeout(() => {
queryClient.prefetchQuery(['searchProductsByText'], async () => {
if (text) {
const data = await fetchProductsByFilter(text);
setProducts(data);
setLoading(false);
return data;
}
});
}, 300);
return () => clearTimeout(delayed);
}, [text]);
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-3">search/filter menu</div>
<div className="col-md-9">
{loading ? (
<h4 className="text-danger">Loading...</h4>
) : (
<h4 className="text-danger">Products</h4>
)}
{products.length < 1 && <p>No products found</p>}
<div className="row pb-5">
{products.map((item) => (
<div key={item._id} className="col-md-4 mt-3">
<ProductCard product={item} />
</div>
))}
</div>
</div>
</div>
</div>
);
};
// async function getServerSideProps(context) {}
export default Shop;
我觉得这不是很地道。使用 react-query,使用过滤器的关键是将它们 放入 查询键中。由于每次键更改时 react-query 都会重新获取,因此每次更改过滤器时都会重新获取,这通常是您想要的。这是一种非常明确的做事方式。根本不需要useEffect。
如果在从 select 中选择某项或单击应用按钮时发生这种情况,这就是您真正需要的:
const [filter, setFilter] = React.useState(undefined)
const { data, isLoading } = useQuery(
['products', filter],
() => fetchProducts(filter)
{ enabled: Boolean(filter) }
)
在这里,只要过滤器是 undefined
,我就会另外禁用查询 - 一旦我们调用 setFilter
.
如果涉及在文本字段中键入内容,我建议进行一些去抖动以避免触发过多请求。 useDebounce hook 对此非常有用。你仍然有 useState
,但你会使用查询的去抖动值:
const [filter, setFilter] = React.useState(undefined)
const debouncedFilter = useDebounce(filter, 500);
const { data, isLoading } = useQuery(
['products', debouncedFilter],
() => fetchProducts(debouncedFilter)
{ enabled: Boolean(debouncedFilter) }
)
如果在从 select 中选择某项或单击应用按钮时发生这种情况,这就是您真正需要的:
const [filter, setFilter] = useState<string>('')
const isEnabled = Boolean(filter)
const { data, isLoading } = useQuery(
['products', filter],
() => fetchProducts(filter)
{ enabled: enabled: filter ? isEnabled : !isEnabled, }
)
<input type="text" onChange={(e) => setFilter(e.target.value)}/>