如何在React Router v6中离开/关闭特定页面时发起请求?
解决React Router v6中页面卸载/导航时调用GraphQL Mutation的问题
核心问题分析
你遇到的问题本质是不同场景下的页面/组件销毁时机与异步请求的兼容性:
- 应用内导航(含浏览器后退):触发React组件卸载,React的
useEffect清理函数会执行,但常规异步请求可能被组件卸载中断 - 页面卸载(关闭标签/浏览器、刷新):触发浏览器的
beforeunload事件,但普通异步请求会被浏览器终止
可行解决方案:分场景覆盖 + 可靠请求方式
我们需要针对两种场景分别处理,同时使用浏览器提供的可靠API确保请求完成:
1. 封装通用的卸载请求函数
使用navigator.sendBeacon(优先)或fetch加keepalive参数,确保请求能在页面卸载时顺利完成:
const sendMutationOnUnload = async (mutationQuery, variables) => { // 构造GraphQL标准请求体 const requestBody = JSON.stringify({ query: mutationQuery, variables: variables }); if (navigator.sendBeacon) { // sendBeacon 是浏览器专为卸载场景设计的API,后台执行不阻塞页面 const blob = new Blob([requestBody], { type: 'application/json' }); navigator.sendBeacon('/graphql', blob); } else { // 降级方案:使用fetch的keepalive参数确保请求完成 await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', // 若需认证,添加你的token头,例如: // 'Authorization': `Bearer ${localStorage.getItem('authToken')}` }, body: requestBody, keepalive: true }); } };
2. 在目标页面组件中实现双场景监听
import { useEffect, useCallback } from 'react'; import { useBeforeUnload } from 'react-router-dom'; // 你的GraphQL Mutation定义 const MY_TARGET_MUTATION = ` mutation RecordPageExit($pageId: String!) { recordPageExit(pageId: $pageId) { success } } `; const TargetPage = () => { // 替换为你的mutation变量 const mutationVars = { pageId: 'user-dashboard' }; // 处理【应用内导航/浏览器后退】:组件卸载时触发 useEffect(() => { return async () => { await sendMutationOnUnload(MY_TARGET_MUTATION, mutationVars); }; }, [mutationVars]); // 处理【关闭标签/浏览器/刷新】:页面卸载时触发 const handleBeforeUnload = useCallback(() => { sendMutationOnUnload(MY_TARGET_MUTATION, mutationVars); // 若不需要提示用户,返回undefined即可;返回字符串会触发浏览器默认离开确认框 return '确定要离开当前页面吗?'; }, [mutationVars]); useBeforeUnload(handleBeforeUnload); return ( <div> {/* 页面内容 */} </div> ); }; export default TargetPage;
为什么之前的方案失效?
useEffect清理函数:直接调用Apollo Client的异步mutation时,组件卸载会中断未完成的请求,改用sendBeacon/keepalive fetch可避免此问题visibilitychange事件:仅监听页面可见性变化(最小化、切标签),与导航/卸载场景无关beforeunload事件:之前的异步mutation被浏览器终止,sendBeacon是浏览器专为这类场景设计的API,会保证请求后台完成
注意事项
- 认证处理:若API需要认证,确保请求携带正确的凭证(如token或cookie),cookie需满足SameSite和Secure要求
- 浏览器兼容性:
navigator.sendBeacon支持所有现代浏览器,降级方案可覆盖旧版浏览器 - 自定义提示限制:浏览器会忽略
beforeunload的自定义提示文字,统一显示系统默认提示,无法完全自定义
内容的提问来源于stack exchange,提问作者wowthatsatoughone
相关产品推荐
相关产品推荐

