我目前正在尝试找到一种显示自定义组件(如Modal)的方法,以使用Prompt
组件来确认路线更改。
Promp
组件的默认行为是显示带有消息的确认对话框,如您在此Example: React Router: Preventing Transitions.中所见
注意:我正在使用<BrowserRouter>
组件。
路由器具有一个名为prop
的{{1}},可用于自定义getUserConfirmation
组件的行为。
<Prompt>
我要做什么:
// this is the default behavior
function getConfirmation(message, callback) {
const allowTransition = window.confirm(message);
callback(allowTransition);
}
<BrowserRouter getUserConfirmation={getConfirmation} />;
状态设置为true,以显示confirm
组件<Confirm>
从callback
函数传递到getConfirmation
组件,以使用<Confirm>
进行转换,并使用{{1 }}来阻止它。true
调用回调。false
这是 App.js 呈现的内容:
true or false
问题出在哪里:
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>
);
变量/参数仍在范围内。这样一切正常。confirm
对话框时,该函数将一直运行。而且,当我单击callback
组件内的确认按钮时,confirm
不再存在。问题
有人知道使用<Confirm>
来实现此行为的方法(使用自定义组件而不是确认对话框来防止路由更改)吗?
来自CodeSandbox的完整代码:
callback
答案 0 :(得分:0)
受此discussion和此example的启发,我能够使我的示例正常工作。
问题在于创建<Confirm>
时,setConfirmCallback()
调用尚未完成。因此<Confirm>
组件无法使用callback
中的getUserConfirmation
。
所以我更改了这一行:
FROM:
setConfirmCallback(callback);
TO:
setConfirmCallback(()=>callback);
现在可以使用了!
完整代码沙盒代码:
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);
答案 1 :(得分:0)
我为我的案例找到了一个简单的解决方法。我无法分享整个组件,只能分享片段。
function App() {
const [showForm, setShowForm] = useState(true);
const [tasks, setTasks] = useState([]);
const [isSubmitted, setIsSubmitted] = useState(false);
//Fetch tasks from server
const fetchData = () => {
fetch(
"https://react-task-tracker-8e519-default-rtdb.firebaseio.com/tasks.json"
)
.then((response) => {
return response.json();
})
.then((data) => {
const tasks = [];
//Convert the data to an array so i can map over it
for (const key in data) {
const task = {
id: key,
...data[key],
};
tasks.push(task);
}
setTasks(tasks);
});
};
useEffect(() => {
if (isSubmitted) {
fetchData();
setIsSubmitted(false);
}
}, [isSubmitted]);
//Show/Hide form
const onAddHandler = () => {
setShowForm(!showForm);
};
const formSubmitted = () => {
setIsSubmitted(true);
console.log(isSubmitted);
};
return (
<Container>
<Header click={onAddHandler} isShown={showForm}></Header>
{showForm ? <Form fs={formSubmitted}></Form> : ""}
<Tasks tasks={tasks}></Tasks>
</Container>
);
}
export default App;