React Query - useInfiniteQuery,获取下一页时如何避免组件刷新
React Query - useInfiniteQuery, how to avoid component refresh when fetching next page
已经使用 Edamam API 为我的食谱应用实现了无限滚动功能,但我遇到了这个问题:
当我到达页面底部并开始获取下一页时,该组件会进行全面刷新,然后会显示每个页面的所有项目。
我想要的是,当我到达底部时,它开始抓取(在底部显示我的微调器和其他东西)并在底部呈现下一页,而不刷新整个页面。
这是我的代码:
const RecipesGrid = ({ query }) => {
const getRecipes = async (pageParam) => {
try {
const path = pageParam
? pageParam
: `https://api.edamam.com/api/recipes/v2?q=${query}&app_id=${process.env.REACT_APP_APP_ID}&app_key=${process.env.REACT_APP_API_KEY}&type=public`;
const response = await axios.get(path);
return response.data;
} catch (error) {
console.log(error);
}
};
useEffect(() => {
const onScroll = (event) => {
const { scrollHeight, scrollTop, clientHeight } =
event.target.scrollingElement;
if (scrollHeight - scrollTop <= clientHeight * 1.2) {
fetchNextPage();
}
};
document.addEventListener("scroll", onScroll);
return () => document.removeEventListener("scroll", onScroll);
// eslint-disable-next-line
}, []);
const {
data,
isFetching,
isFetchingNextPage,
status,
hasNextPage,
fetchNextPage,
} = useInfiniteQuery(
["recipes", query],
({ pageParam = "" }) => getRecipes(pageParam),
{
getNextPageParam: (lastPage) =>
lastPage._links.next ? lastPage._links.next.href : undefined,
}
);
if (isFetching || status === "loading") {
return <Spinner />;
}
if (status === "error") {
return <div>Whoops! something went wrong...Please, try again</div>;
}
return (
<div className={styles.Recipes}>
{data?.pages.map((item, index) => (
<React.Fragment key={index}>
{item.hits.map((recipe) => (
<Recipe recipe={recipe} key={recipe.recipe.uri} />
))}
{item.hits.length === 0 ? (
<Empty message="No results found!" />
) : null}
{!hasNextPage && item.hits.length !== 0 && (
<Empty message="No more recipes!" />
)}
</React.Fragment>
))}
{isFetchingNextPage && <Spinner />}
</div>
);
};
export default RecipesGrid;
我认为您正在卸载整个列表,因为您只在此处呈现加载微调器:
if (isFetching || status === "loading") {
return <Spinner />;
}
只要请求在进行中,isFething
始终为真。当您获取下一页时也是如此,因此您提前 return 进入并删除您的列表。从 if 语句中删除 isFetching
应该可以解决它,因为无论如何您都会通过以下方式显示后台加载指示器:
{isFetchingNextPage && <Spinner />}
此外,您的错误处理将不起作用,因为您通过捕获它们进行记录而不是重新抛出它们来将错误转换为已解决的承诺:
} catch (error) {
console.log(error);
}
对于类似的事情,请使用 onError
回调。
已经使用 Edamam API 为我的食谱应用实现了无限滚动功能,但我遇到了这个问题:
当我到达页面底部并开始获取下一页时,该组件会进行全面刷新,然后会显示每个页面的所有项目。
我想要的是,当我到达底部时,它开始抓取(在底部显示我的微调器和其他东西)并在底部呈现下一页,而不刷新整个页面。
这是我的代码:
const RecipesGrid = ({ query }) => {
const getRecipes = async (pageParam) => {
try {
const path = pageParam
? pageParam
: `https://api.edamam.com/api/recipes/v2?q=${query}&app_id=${process.env.REACT_APP_APP_ID}&app_key=${process.env.REACT_APP_API_KEY}&type=public`;
const response = await axios.get(path);
return response.data;
} catch (error) {
console.log(error);
}
};
useEffect(() => {
const onScroll = (event) => {
const { scrollHeight, scrollTop, clientHeight } =
event.target.scrollingElement;
if (scrollHeight - scrollTop <= clientHeight * 1.2) {
fetchNextPage();
}
};
document.addEventListener("scroll", onScroll);
return () => document.removeEventListener("scroll", onScroll);
// eslint-disable-next-line
}, []);
const {
data,
isFetching,
isFetchingNextPage,
status,
hasNextPage,
fetchNextPage,
} = useInfiniteQuery(
["recipes", query],
({ pageParam = "" }) => getRecipes(pageParam),
{
getNextPageParam: (lastPage) =>
lastPage._links.next ? lastPage._links.next.href : undefined,
}
);
if (isFetching || status === "loading") {
return <Spinner />;
}
if (status === "error") {
return <div>Whoops! something went wrong...Please, try again</div>;
}
return (
<div className={styles.Recipes}>
{data?.pages.map((item, index) => (
<React.Fragment key={index}>
{item.hits.map((recipe) => (
<Recipe recipe={recipe} key={recipe.recipe.uri} />
))}
{item.hits.length === 0 ? (
<Empty message="No results found!" />
) : null}
{!hasNextPage && item.hits.length !== 0 && (
<Empty message="No more recipes!" />
)}
</React.Fragment>
))}
{isFetchingNextPage && <Spinner />}
</div>
);
};
export default RecipesGrid;
我认为您正在卸载整个列表,因为您只在此处呈现加载微调器:
if (isFetching || status === "loading") {
return <Spinner />;
}
只要请求在进行中,isFething
始终为真。当您获取下一页时也是如此,因此您提前 return 进入并删除您的列表。从 if 语句中删除 isFetching
应该可以解决它,因为无论如何您都会通过以下方式显示后台加载指示器:
{isFetchingNextPage && <Spinner />}
此外,您的错误处理将不起作用,因为您通过捕获它们进行记录而不是重新抛出它们来将错误转换为已解决的承诺:
} catch (error) {
console.log(error);
}
对于类似的事情,请使用 onError
回调。