В настоящее время я пытаюсь найти способ отображения пользовательского компонента (например, модального) для подтверждения изменений маршрута с использованием компонента 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>
- И япопытка передать
callback
из функции getConfirmation
компоненту <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);