You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit 场景下如何实现页面导航拦截功能?

方案适配性判断

首先明确你提到的三个方案的适用场景:

  • usePrefetch 完全不适用,该钩子是RTK Query用于提前拉取接口数据做缓存的能力,和导航拦截没有任何关联,直接排除
  • 手动封装history.push等跳转方法的方案仅能覆盖你主动调用封装方法的跳转场景,无法拦截浏览器前进后退、Link组件点击、页面刷新等行为,维护成本高,不推荐
  • 最优方案是React Router官方导航拦截能力 + Redux Toolkit状态读取,逻辑解耦,能覆盖所有跳转场景,实现成本最低

实现步骤

首先你需要在Redux Toolkit的对应slice中暴露队列长度的选择器,方便组件读取状态:

// queueSlice.js 示例
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  taskList: [] // 你的队列存储字段
}
const queueSlice = createSlice({
  name: 'queue',
  initialState,
  reducers: {
    // 你的队列增删改逻辑
  }
})
// 导出队列长度选择器
export const selectQueueLength = state => state.queue.taskList.length
export default queueSlice.reducer

如果你使用React Router v5

直接用内置的Prompt组件配合Redux状态即可:

import { Prompt } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { selectQueueLength } from './queueSlice'

function YourBusinessPage() {
  const queueLength = useSelector(selectQueueLength)
  const needBlockNavigation = queueLength > 0

  return (
    <>
      {/* 直接硬拦截,不允许跳转,不需要用户确认 */}
      <Prompt
        when={needBlockNavigation}
        message={() => false}
      />
      {/* 如果需要弹出确认框让用户选择,替换为下面的写法 */}
      {/*
      <Prompt
        when={needBlockNavigation}
        message="当前队列还有未处理任务,确定要离开页面吗?"
      />
      */}
      {/* 页面其他业务内容 */}
    </>
  )
}

如果你使用React Router v6

v6版本移除了Prompt组件,使用官方提供的useBlocker钩子实现:

import { useBlocker } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { selectQueueLength } from './queueSlice'

function YourBusinessPage() {
  const queueLength = useSelector(selectQueueLength)
  const needBlockNavigation = queueLength > 0

  // 硬拦截:直接禁止所有跳转
  useBlocker(() => needBlockNavigation)

  /* 如果需要弹出自定义确认框,替换为下面的逻辑
  const blocker = useBlocker(() => needBlockNavigation)
  useEffect(() => {
    if (blocker.state === 'blocked') {
      const isConfirmed = window.confirm('当前队列还有未处理任务,确定要离开页面吗?')
      isConfirmed ? blocker.proceed() : blocker.reset()
    }
  }, [blocker])
  */

  // 页面其他业务内容
  return <></>
}

额外场景:拦截页面刷新/关闭

如果需要拦截浏览器刷新、关闭标签页的行为,需要额外监听beforeunload事件:

useEffect(() => {
  const handleBeforeUnload = (e) => {
    if (queueLength > 0) {
      e.preventDefault()
      e.returnValue = ''
    }
  }
  window.addEventListener('beforeunload', handleBeforeUnload)
  return () => window.removeEventListener('beforeunload', handleBeforeUnload)
}, [queueLength])

全局拦截方案

如果需要对所有页面生效该拦截规则,只需要把上述逻辑放在全局Layout组件中即可,不需要每个页面单独引入。

内容的提问来源于stack exchange,提问作者data one

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:45:04