【问题标题】:react-router v4: prevent transition with custom hook instead of Promptreact-router v4:使用自定义钩子而不是提示来防止转换
【发布时间】:2017-08-24 15:10:24
【问题描述】:

react-router v3 中,我一直在使用router.setRouteLeaveHook 检查表单是否有未保存的更改,如果有,则返回false 以防止转换。然后我会显示一个带有 3 个按钮的自定义引导模式对话框:Save Changes、Discard Changes 和 Stay Here。

我不能使用react-router v4 的Prompt 组件来执行此操作,因为无法自定义浏览器确认对话框中显示的按钮。他们似乎摆脱了任何取消转换的方法,只允许您在浏览器确认对话框中要求用户批准转换。

我尝试查看Promptit just passes the dialog message to history 的代码,所以我不知道如何设置 v3 样式的路由离开钩子。

是否有可能,或者react-router 开发人员出于某种原因故意决定删除此功能?

【问题讨论】:

    标签: javascript react-router history.js html5-history


    【解决方案1】:

    根据the history package docs,您可以将window.confirm替换为您喜欢的任何内容:

    默认情况下,window.confirm 用于向用户显示提示消息。如果您需要覆盖此行为(或者如果您正在使用不假定 DOM 环境的 createMemoryHistory),请在创建历史对象时提供 getUserConfirmation 函数。

    因此,如果您想使用自己的对话框,应该可以通过以下方式完成:

    const history = createHistory({
      getUserConfirmation(message, callback) {
        showMyCustomDialog(message)
          .then(result => callback(result === 'The YES button'))
      }
    })
    

    这意味着您设置的任何getUserConfirmation 消息都是为整个会话设置的,但您可以将其抽象到导航阻止层,该层包含对话框的其他详细信息,例如标题、按钮文本、颜色等。

    或者,您可以劫持message 参数并将其用于对话框配置,尽管这可能有点难听。但这不是一个完美的系统,所以你所做的任何事情都可能有点麻烦。

    React Router v4 允许您在创建路由器时传递此方法(请参阅here):

    <BrowserRouter getUserConfirmation={yourConfirmationFunction} />
    

    【讨论】:

    • 谢谢,我没发现!这当然是真的,我所做的任何事情都可能是黑客行为。旧路线离开钩子的情况并非如此。
    • 一种简单粗暴的方法是使用message 作为对象键,并设置可能的导航拦截器字典。例如,blockers = {myBlocker: cb =&gt; dialog.then(cb)},然后在您的用户确认功能中,调用blockers[message](callback)。我最近完成了 v3 => v4 升级,发现我只使用一个对话框,有时只是完全阻止导航(例如,当显示模式时),所以将对话框代码烘焙到确认函数中对我来说就足够了。如果您愿意扩展其功能,我相信该项目将获得 PR!
    【解决方案2】:

    可以使用Prompt 显示自定义对话。致谢及详解here

    Prompt 需要一个 message 属性,这里我们可以使用自定义函数进行对话,它应该返回 false 以防止导航。

    const BlockingPage = () => {
      const [block, setBlock] = useState(true);
      
      const blockedNavigation = (nLocation) => {
        //nLocation gives the next location object
        
        /**
          * Your custom logic
          *
        **/
        
        //required to block navigation
        return false
      } 
    
      return(
        <div>
          <Prompt when={block} message={blockedNavigation}/>
        </div>
      )
    
    } 
    

    【讨论】:

    • 啊酷,我不确定这是我提交 OP 时的功能
    • reactrouter.com/core/api/Prompt 的文档有点暗示这一点,但它忽略了您可以 return false 阻止导航的事实
    【解决方案3】:

    我认为这是不可能的。 react-router-v4 使用了一个名为 history 的包,该包又使用了 HTML5 历史 API。历史 API 仅在您点击后退按钮 (onpopstate) 时通知您,如果您考虑一下,这很有意义,因为您不想让网站拥有不让您在页面之间移动的权力。

    您可以做的最好的事情是window onbeforeunload event,它会创建一个提示,让您要求用户确认,但这正是 react-router 公开供您使用的内容。

    你可以通过猴子修补 react-router 的内部历史对象来获得一些你想要的功能,这样你就可以添加你自己的行为。但是有一点需要注意,这只有在你 react-router 的 &lt;Link /&gt; 组件和朋友时才有效,所以你将无法拦截刷新和其他你可能想要的东西。

    如果您想走那条路,请告诉我,我可以为您提供一些有关其工作原理的见解或代码示例,我会更新我的答案。

    【讨论】:

    • 但是 react-router-v3 如何防止转换?它还使用历史记录,因此除非他们从历史记录中删除此功能,否则我不明白您在说什么。
    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 2019-03-19
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多