use*_*462 2 javascript reactjs react-router react-router-dom
我的应用程序有两个页面:Step1和Step2. Step1有一个复选框,如果选中它会阻止导航,还有一个Step2单击时导航到的下一步按钮。Step2有一个“上一个”按钮,Step1单击时会导航回。
根据本教程,如果选中复选框,我将使用对象的block方法createBrowserHistory来阻止路由更改Step1:
const unblock = useRef();
useEffect(() => {
unblock.current = history.block((tx) => {
if (block.current.checked) {
const promptMessage = "Are you sure you want to leave?";
if (window.confirm(promptMessage)) {
unblock.current();
tx.retry();
}
} else {
console.log("tfgx");
unblock.current();
tx.retry();
}
});
}, []);
Run Code Online (Sandbox Code Playgroud)
我还必须将低级<Router>(not <BrowserRouter>) 中的 history 道具设置为createBrowserHistory对象,如下所示:
<Router history={createBrowserHistory()}>
...
</Router>
Run Code Online (Sandbox Code Playgroud)
但这会阻止路由被正确呈现。我认为这可能与<Switch>无法正确读取位置对象有关。如果我使用<BrowserRouter>,位置物体看起来是这样的:{pathname: "/step1", ... key: "7sd45"}。但是当我使用时<Router={createBrowserHistory()}>,位置对象看起来像这样{action: "PUSH", location: {pathname: "/step1", ... key: "7sd45"}}。(我也收到警告You cannot change <Router history>。)
如果选中“阻止导航”复选框,我想要的结果是阻止导航,否则取消阻止。如果导航解锁时位置发生变化,我希望正确呈现相应的路线。
React Router v5 文档中关于 createBrowserHisory 的部分很少,并且使用它的示例并不多,所以如果有人能对此有所了解,我将不胜感激。
编辑:传递location.location到<Switch>似乎修复它(更新演示)。但是如果我调用useLocationinsideStep1并打印结果(第 17-18 行),我得到{pathname: "/step1", ... key: "7sd45"}而不是{action: "PUSH", location: {pathname: "/step1", ... key: "7sd45"}}. 为什么是这样?
此外,如果用户在导航被阻止时尝试去另一个位置,我的自定义提示会按预期显示(“您确定要离开吗”和“确定”和“取消”按钮)。但是,如果他们通过单击“取消”取消此操作,则会出现浏览器自己的对话框 -
在 Chrome 中:
在 Firefox 中:
在我的提示被关闭后,是否可以取消浏览器提示?
The router context's history object also has a block function but it works a little differently. It takes a callback that consumes location and action arguments.
history.block((location, action) => {...});
Run Code Online (Sandbox Code Playgroud)
Returning false from the callback blocks the navigation transition, returning true allows the transition to go through.
React.useEffect(() => {
const unblock = history.block((location, action) => {
if (checkBlockingCondition) {
return window.confirm("Navigate Back?");
}
return true;
});
return () => {
unblock();
};
}, []);
Run Code Online (Sandbox Code Playgroud)
Alternatively, react-router-dom suggests using the Prompt component to conditionally block route transitions. Your code is very close to their preventing transitions example.
Updates to your last codesandbox:
Prompt component.code
import {
BrowserRouter as Router,
Prompt, // <-- import Prompt
Redirect,
Switch,
Route,
useLocation
} from "react-router-dom";
const Step1 = ({ id, history }) => {
const [isBlocking, setIsBlocking] = useState(false);
return (
<form
id={id}
onSubmit={(e) => {
e.preventDefault(); // <-- prevent default form action, i.e. page reload
history.push("/step2");
}}
>
<label>
Block navigation
<input
type="checkbox"
onChange={(e) => setIsBlocking(e.target.checked)}
/>
</label>
<br />
<br />
<button type="submit">Next</button>
<Prompt
when={isBlocking} // <-- blocking condition
message="Are you sure you want to leave?"
/>
</form>
);
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6104 次 |
| 最近记录: |