Next.js+react-query:如何实现初始数据预取且仅过滤器变更时重取?
问题分析与解决方案
问题现状
在Next.js项目中使用react-query预取数据,通过getStaticProps获取初始数据传入组件,期望页面加载时直接使用初始数据(不触发isLoading),仅在过滤器修改时重新请求数据。但当前页面加载时isLoading会先显示true,不符合预期。
相关代码如下:
组件代码
function JobSearch(props) { const [pageNumber, setPageNumber] = useState(1); const [company, setCompany] = useState(""); const [remote, setRemote] = useState(""); const [orderBy, setOrder] = useState("date"); const [location, setLocation] = useState(""); const { data: jobData, isLoading } = useQuery( ["jobs", pageNumber, company, remote, orderBy, location], () => fetchJobs(pageNumber, company, remote, orderBy, location), { initialData: props.jobs } ); console.log(isLoading); }
过滤器示例
<Select style={{ width: 200 }} onChange={(value) => { setRemote(value); setPageNumber(1); }} defaultValue=""> <option value="">Qualquer</option> <option value="true">Remoto</option> <option value="false">Presencial</option> </Select>
getStaticProps代码
export async function getStaticProps() { const pageNumber = 1; const orderBy = "date"; jobs = await fetchJobs(pageNumber, orderBy); return { props: { jobs, }, }; }
问题原因
- queryKey与初始数据的请求参数不匹配:
getStaticProps中调用fetchJobs只传入了pageNumber和orderBy,但组件中useQuery的fetchJobs传入了5个参数(其余初始为空字符串)。这导致react-query认为当前queryKey对应的缓存不存在,会自动发起新请求,触发isLoading。 - react-query默认的重新验证机制:react-query默认
staleTime为0,即数据一旦挂载就会被标记为"过时",会自动后台重新请求数据,导致isLoading短暂变为true。
解决方案
1. 对齐初始请求参数与queryKey
修改getStaticProps,确保调用fetchJobs时传入的参数与组件初始状态的参数完全一致,这样初始数据对应的queryKey才会和组件的初始queryKey匹配:
export async function getStaticProps() { const pageNumber = 1; const company = ""; const remote = ""; const orderBy = "date"; const location = ""; const jobs = await fetchJobs(pageNumber, company, remote, orderBy, location); return { props: { jobs, }, }; }
2. 设置staleTime禁止自动重新验证
在useQuery配置中添加staleTime: Infinity,这样react-query会认为初始数据永远是新鲜的,不会自动发起重新请求,只有当queryKey变化(过滤器修改)时才会重新获取数据:
const { data: jobData, isLoading } = useQuery( ["jobs", pageNumber, company, remote, orderBy, location], () => fetchJobs(pageNumber, company, remote, orderBy, location), { initialData: props.jobs, staleTime: Infinity // 禁止自动重新验证 } );
额外优化:控制isLoading的显示逻辑(可选)
如果仍担心边界情况,可以结合isInitialLoading来判断初始加载状态(react-query v3+支持该属性),只在首次无初始数据时显示加载状态:
const { data: jobData, isLoading, isInitialLoading } = useQuery( // ... 其他配置 ); // 仅在真正的首次加载(无初始数据)时显示加载 if (isInitialLoading) { return <Loading />; }
内容的提问来源于stack exchange,提问作者Vegas
相关产品推荐
相关产品推荐

