异步调用后用useSearchParams更新搜索参数导致跳回前页,如何阻止?
问题描述
在异步调用完成后尝试使用useSearchParams钩子更新搜索参数,但如果在异步调用结束前导航至其他页面,异步调用完成时系统会尝试更新搜索参数并跳转回之前的页面。
示例代码:
import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import Button from "@mui/material/Button"; import { useNavigate, useSearchParams } from "react-router-dom"; const Assets = () => { const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const onPress = async () => { navigate("/trackers"); const response = await fetch("https://randomuser.me/api/", { method: "GET" }); await response.json(); setSearchParams({ assetId: "1" }); }; return ( <List> <ListItem>test-asset-1</ListItem> <ListItem>test-asset-2</ListItem> <ListItem>test-asset-3</ListItem> <ListItem>test-asset-4</ListItem> <ListItem> <Button onClick={onPress}>Press</Button> </ListItem> </List> ); }; export default Assets;
原本期望仅更新搜索参数,但实际会跳转回之前的URL,需要确保导航至其他页面后不再更新搜索参数。
解决方案
核心思路是跟踪组件的挂载状态,在异步操作完成后仅当组件仍处于挂载状态时,才执行更新搜索参数的操作。以下是具体实现:
基础实现:检查组件挂载状态
import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import Button from "@mui/material/Button"; import { useNavigate, useSearchParams, useRef, useEffect } from "react-router-dom"; const Assets = () => { const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); // 用ref记录组件是否处于挂载状态 const isMounted = useRef(true); useEffect(() => { // 组件卸载时更新状态 return () => { isMounted.current = false; }; }, []); const onPress = async () => { navigate("/trackers"); try { const response = await fetch("https://randomuser.me/api/", { method: "GET" }); await response.json(); // 仅当组件仍挂载时执行搜索参数更新 if (isMounted.current) { setSearchParams({ assetId: "1" }); } } catch (error) { console.error("请求失败:", error); } }; return ( <List> <ListItem>test-asset-1</ListItem> <ListItem>test-asset-2</ListItem> <ListItem>test-asset-3</ListItem> <ListItem>test-asset-4</ListItem> <ListItem> <Button onClick={onPress}>Press</Button> </ListItem> </List> ); }; export default Assets;
优化方案:结合AbortController取消无效请求
除了检查挂载状态,还可以用AbortController在组件卸载时取消未完成的网络请求,避免不必要的资源消耗:
const onPress = async () => { navigate("/trackers"); const controller = new AbortController(); const signal = controller.signal; // 组件卸载时取消请求 useEffect(() => { return () => { controller.abort(); }; }, []); try { const response = await fetch("https://randomuser.me/api/", { method: "GET", signal }); await response.json(); if (isMounted.current) { setSearchParams({ assetId: "1" }); } } catch (error) { // 忽略请求取消的错误 if (error.name !== "AbortError") { console.error("请求失败:", error); } } };
原理说明
useRef的isMounted变量会在组件挂载时初始化为true,卸载时通过useEffect的清理函数设为false,确保异步操作完成后能判断组件是否还存在。- 只有当组件仍处于挂载状态时,才执行
setSearchParams,避免在用户已导航到其他页面后修改原页面的搜索参数,从而防止不必要的页面跳转。 AbortController可以在组件卸载时终止未完成的网络请求,减少无效的网络开销,同时避免请求完成后触发后续逻辑。
内容的提问来源于stack exchange,提问作者Nitin Agrawal
相关产品推荐
相关产品推荐

