在我的应用程序中,我使用react-router v5和react/typescript,我有一个使用react-query并获取一些数据的组件。目前,它仅在第一次渲染组件时获取数据,当导航请求不会被取消并且导航回来时,它不会发出新请求。该组件接受一个 id 参数,该参数根据 id 获取数据,因此它需要刷新组件,或者可能需要将方法添加到 useEffect
Hook 中?
路由组件
import React from 'react';
import { BrowserRouter, Route, Switch} from 'react-router-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import { RouteComponentProps } from "react-router-dom";
import Component1 from '../Component1';
import Component2 from '../Component2';
const queryClient = new QueryClient()
const Routing: React.FunctionComponent = () => {
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<Switch>
<Route exact path="/" component={Component1} />
<Route path="/details/:id" render={(props: RouteComponentProps<any>) => <Component2 {...props}/>} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
</QueryClientProvider>
)
}
export default Routing;
组件2(id)
import React from 'react';
import { useQuery } from 'react-query';
import { RouteComponentProps, useLocation } from "react-router-dom";
interface stateType {
model: { pathname: string },
start: { pathname: string | Date }
}
const Component2: React.FunctionComponent<RouteComponentProps<any>> = (props) => {
const { state } = useLocation<stateType>();
let alertInnerId = props.match.params.id;
const fetchChart = async () => {
const res = await fetch(`/detail/${id}`);
return res.json();
};
const { data, status } = useQuery('planeInfo', fetchPlane, {
staleTime: 5000,
});
return (
<>
{status === 'error' && (
<div className="mt-5">Error fetching data!</div>
)}
{status === 'loading' && (
<div className="mt-5">Loading data ...
</div>
)}
{status === 'success' && (
{data.map(inner => {
return (
<p>{inner.id}</p>
)
})}
)}
</div>
</>
)
}
export default Component2;
在组件 1 中,我以编程方式导航:
onClick={() => history.push(`/detail/${id}}`, { model: plane.model, start: formattedStartDateTime })}>
无论是通过编程方式还是正常方式,它仍然是一样的。
最佳答案
[...] and navigating back it does not make a new request.
首先,根据您的代码,根据设置为 useQuery
本身选项的 staleTime
选项,缓存应每五秒失效一次。因此,每次安装 useQuery Hook 时(例如在路由更改时),如果过去了五秒,则应发出新请求。尽管您引用的 id
似乎未定义,但您的代码似乎不完整。
无论如何,由于您正在请求带有 ID 的资源的详细信息,因此您应该考虑使用如下查询键:[planeInfo, id]
而不是 planeInfo
独自的。来自 documentation :
Since query keys uniquely describe the data they are fetching, they should include any variables you use in your query function that change. For example:
function Todos({ todoId }) {
const result = useQuery(['todos', todoId], () =>
fetchTodoById(todoId))
}
处理取消导航请求:
您无法将 React Query 中的 useQuery
Hook 包装在 useEffect
Hook 中,但您可以使用 useEffect
的返回函数> 清理您的 useQuery
请求,在组件卸载时有效地取消请求。使用 useQuery
有两种方法(可能更多)取消请求:
- 使用
useQuery
返回的对象上公开的remove
方法 - 使用
QueryClient
方法:cancelQueries
( see: useQuery
reference here )
see: QueryClient
reference here具体来说cancelQueries
将 remove
与 useEffect
结合使用
(我只保留了您代码的相关部分)
const Component2: React.FunctionComponent <RouteComponentProps<any>> = (props) => {
const fetchChart = async() => {
const res = await fetch(`/detail/${id}`);
return res.json();
};
const {
data,
status,
/** access the remove method **/
remove
} = useQuery('planeInfo', fetchPlane, {
staleTime: 5000,
});
useEffect(() => {
/** when this component unmounts, call it **/
return () => remove()
/** make sure to set an empty deps array **/
}, [])
/** the rest of your component **/
}
像这样调用remove
将取消任何正在进行的请求,但顾名思义,它还会从缓存中删除查询。根据您是否需要将数据保留在缓存中,这可能是也可能不是可行的策略。如果您需要保留数据,可以使用 canceQueries
方法。
将 cancelQueries
与 useEffect
结合使用
与之前非常相似,只是这里您需要从路由组件文件中导出 queryClient
实例(正如您在其中定义的那样),然后导入该 QueryClient
实例code> 进入 Component2 并从 useEffect
调用缓存键上的 cancelQueries
:
import { queryClient } from "./routing-component"
const Component2: React.FunctionComponent <RouteComponentProps<any>> = (props) => {
const fetchChart = async() => {
const res = await fetch(`/detail/${id}`);
return res.json();
};
const {
data,
status,
} = useQuery(['planeInfo', id], fetchPlane, {
staleTime: 5000,
});
useEffect(() => {
/** when this component unmounts, call it **/
return () => queryClient.cancelQueries(['planeInfo', id], {exact: true, fetching: true})
}, [])
/** the rest of your component **/
}
在这里您可以看到我已经按照之前的建议实现了查询键以及 id。您会明白为什么对缓存对象进行更精确的引用会很有好处。我还使用两个 query filters :精确
和获取
。将 exact
设置为 true 将确保 React Query 不使用模式匹配并取消更广泛的查询集。您可以决定这对于您的实现需求是否是必要的。将 fetching 设置为 true 将确保 React Query 包含并取消当前正在获取数据的查询。
请注意,通过依赖 useEffect
,在某些情况下,由于用户离开页面(例如模态)以外的因素,其父组件可能会被卸载。在这种情况下,您应该将 useQuery
在组件树中向上移动到一个仅在用户导航时卸载的组件中,然后将 useQuery
的结果传递给子组件组件作为 props,以避免过早取消。
或者,您可以使用 Axios 而不是 fetch。使用 Axios,您可以 cancel a request using a global cancel token ,并将执行该取消与 React Router 的 useLocation ( example here ) 结合起来。当然,您也可以将监听路由更改的 useLocation
与 QueryClient.cancelQueries
结合起来。事实上,有很多可能的方法来解决你的问题。
关于javascript - React 路由器/React 查询不会取消/在导航上发出请求 - React/TypeScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69651014/