#javascript #reactjs #next.js #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 amp;amp; <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;
Ответ №1:
Мне это не кажется очень идиоматичным. С помощью react-запроса ключ к использованию фильтров заключается в том, чтобы поместить их в ключ запроса. Поскольку react-запрос выполняет повторную выборку при каждом изменении ключа, вы будете получать повторную выборку при каждом изменении фильтра, что обычно и требуется. Это очень декларативный способ ведения дел. Никакого эффекта от использования вообще не требуется.
Если это происходит при выборе чего-либо из списка «Выбрать» или нажатии кнопки «Применить», это действительно все, что вам нужно:
const [filter, setFilter] = React.useState(undefined)
const { data, isLoading } = useQuery(
['products', filter],
() => fetchProducts(filter)
{ enabled: Boolean(filter) }
)
Здесь я дополнительно отключаю запрос до тех пор, пока есть фильтр undefined
— выборка начнется, как только мы вызовем setFilter
.
если требуется ввести текст в текстовое поле, я бы рекомендовал немного отменить, чтобы избежать слишком большого количества запросов. Используемый крючок для прыжка очень хорош для этого. У вас все равно будет useState
, но вы будете использовать отмененное значение для запроса:
const [filter, setFilter] = React.useState(undefined)
const debouncedFilter = useDebounce(filter, 500);
const { data, isLoading } = useQuery(
['products', debouncedFilter],
() => fetchProducts(debouncedFilter)
{ enabled: Boolean(debouncedFilter) }
)
Комментарии:
1. вау, это так круто. Спасибо!!! Многому у тебя учусь.