如何使用react-router <Prompt>显示组件以防止或允许更改路由

cbdeveloper

我目前正在尝试找到一种显示自定义组件(如Modal)的方法,以确认使用该Prompt组件的路线更改

Promp组件的默认行为是显示带有消息的确认对话框,如本例中所示:React Router:防止过渡。

注意:我正在使用该<BrowserRouter>组件。

路由器有一个prop名为getUserConfirmation,您可以使用它自定义<Prompt>组件的行为

// this is the default behavior

function getConfirmation(message, callback) {
  const allowTransition = window.confirm(message);
  callback(allowTransition);
}

<BrowserRouter getUserConfirmation={getConfirmation} />;

我正在尝试做的是:

  • 在父组件APP内
    • 我将confirm状态设置为true,以显示<Confirm>组件
    • 而且我正在尝试callbackgetConfirmation函数传递到<Confirm>组件以对其进行调用,true以允许进行过渡,并false阻止进行过渡
    • true or false如上所示将以默认行为调用回调
function getConfirmation(message, callback) {
    console.log("Inside getConfirmation function...");
    setConfirmCallback(callback);
    setConfirm(true);
    // const allowTransition = window.confirm(message);
    // callback(allowTransition);
  }

这是App.js呈现的内容:

return (
    <Router getUserConfirmation={getConfirmation}>
      <AllRoutes />
      {confirm && (
        <Confirm confirmCallback={confirmCallback} setConfirm={setConfirm} />
      )}
    </Router>
  );

似乎是什么问题:

  • 此时confirm对话框似乎阻止了该功能。因此callback变量/参数仍在范围内。所以一切正常。
  • 当我删除confirm对话框时,该功能将一直运行。当我单击<Confirm>组件内部的确认按钮时,该按钮callback不再存在。

是否有人知道使用以下方法来实现此行为的方法(使用自定义组件而不是确认对话框来防止路由更改)react-router-dom

链接到CodeSandbox

来自CodeSandbox的完整代码:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import {
  BrowserRouter as Router,
  Route,
  Switch,
  Link,
  Prompt
} from "react-router-dom";

import "./styles.css";

function App() {
  console.log("Rendering App...");

  const [confirm, setConfirm] = useState(false);
  const [confirmCallback, setConfirmCallback] = useState(null);

  function getConfirmation(message, callback) {
    console.log("Inside getConfirmation function...");
    setConfirmCallback(callback);
    setConfirm(true);
    // const allowTransition = window.confirm(message);
    // callback(allowTransition);
  }

  return (
    <Router getUserConfirmation={getConfirmation}>
      <AllRoutes />
      {confirm && (
        <Confirm confirmCallback={confirmCallback} setConfirm={setConfirm} />
      )}
    </Router>
  );
}

function Confirm(props) {
  function allowTransition() {
    props.setConfirm(false);
    props.confirmCallback(true);
  }

  function blockTransition() {
    props.setConfirm(false);
    props.confirmCallback(false);
  }

  return (
    <React.Fragment>
      <div>Are you sure?</div>
      <button onClick={allowTransition}>Yes</button>
      <button onClick={blockTransition}>No way</button>
    </React.Fragment>
  );
}

function AllRoutes(props) {
  console.log("Rendering AllRoutes...");
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/comp1" component={Component1} />
    </Switch>
  );
}

function Home(props) {
  console.log("Rendering Home...");
  return (
    <React.Fragment>
      <div>This is Home</div>
      <ul>
        <li>
          <Link to="/comp1">Component1</Link>
        </li>
      </ul>
    </React.Fragment>
  );
}

function Component1(props) {
  console.log("Rendering Component1...");

  const [isBlocking, setIsBlocking] = useState(true);

  return (
    <React.Fragment>
      <Prompt
        when={isBlocking}
        message={location =>
          `Are you sure you want to go to ${location.pathname}`
        }
      />
      <div>This is component 1</div>
      <Link to="/">Home</Link>
    </React.Fragment>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
cbdeveloper

受此讨论和此示例的启发,我能够使我的示例正常工作。

问题是<Confirm>创建时,setConfirmCallback()调用尚未完成。因此,该<Confirm>组件无法使用callbackfrom getUserConfirmation

所以我改变了这一行:

FROM:
  setConfirmCallback(callback);
TO:
  setConfirmCallback(()=>callback);

现在就可以了!

CodeSandbox链接

完整的代码沙盒代码:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import {
  BrowserRouter as Router,
  Route,
  Switch,
  Link,
  Prompt
} from "react-router-dom";

import "./styles.css";

function App() {
  console.log("Rendering App...");

  const [confirm, setConfirm] = useState(false);
  const [confirmCallback, setConfirmCallback] = useState(null);

  function getConfirmation(message, callback) {
    console.log("Inside getConfirmation function...");
    setConfirmCallback(() => callback);
    setConfirm(true);
    // const allowTransition = window.confirm(message);
    // callback(allowTransition);
  }

  return (
    <Router getUserConfirmation={getConfirmation}>
      <AllRoutes />
      {confirm && (
        <Confirm confirmCallback={confirmCallback} setConfirm={setConfirm} />
      )}
    </Router>
  );
}

function Confirm(props) {
  console.log("Rendering Confirm...");
  function allowTransition() {
    props.setConfirm(false);
    props.confirmCallback(true);
  }

  function blockTransition() {
    props.setConfirm(false);
    props.confirmCallback(false);
  }

  return (
    <React.Fragment>
      <div>Are you sure?</div>
      <button onClick={allowTransition}>Yes</button>
      <button onClick={blockTransition}>No way</button>
    </React.Fragment>
  );
}

function AllRoutes(props) {
  console.log("Rendering AllRoutes...");
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/comp1" component={Component1} />
    </Switch>
  );
}

function Home(props) {
  console.log("Rendering Home...");
  return (
    <React.Fragment>
      <div>This is Home</div>
      <ul>
        <li>
          <Link to="/comp1">Component1</Link>
        </li>
      </ul>
    </React.Fragment>
  );
}

function Component1(props) {
  console.log("Rendering Component1...");

  const [isBlocking, setIsBlocking] = useState(true);

  return (
    <React.Fragment>
      <Prompt
        when={isBlocking}
        message={location =>
          `Are you sure you want to go to ${location.pathname}`
        }
      />
      <div>This is component 1</div>
      <Link to="/">Home</Link>
    </React.Fragment>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章