Pra*_*til 8 javascript reactjs react-router-dom
在 React 项目中,我创建了一个弹出模式,当任何用户尝试在输入字段中进行任何更改并导航到其他屏幕时,都会显示该模式。它没有按预期工作,因此浏览了很多帖子来找到解决方案,但没有运气。请参考下面的代码:
useBlock.js
import {useContext, useEffect} from 'react';
import { UNSAFE_NavigationContext as NavigationContext} from 'react-router-dom';
const useBlocker = (blocker, when = true) => {
const navigator = useContext(NavigationContext).navigator
useEffect(() => {
if (!when)
return;
const unblock = navigator.block((tx) => { <-- This line is creating an issue
const autoUnblockingTx = {
...tx,
retry() {
unblock();
tx.retry();
},
};
blocker(autoUnblockingTx);
});
return unblock;
}, [navigator, blocker, when]);
}
export default useBlocker
Run Code Online (Sandbox Code Playgroud)
useCallbackPrompt.js
import { useCallback, useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router';
import useBlocker from './useBlocker';
const useCallbackPrompt = (when) => {
const navigate = useNavigate();
const location = useLocation();
const [showPrompt, setShowPrompt] = useState(false);
const [lastLocation, setLastLocation] = useState(null);
const [confirmedNavigation, setConfirmedNavigation] = useState(false);
const cancelNavigation = useCallback(() => {
setShowPrompt(false);
}, []);
const handleBlockedNavigation = useCallback((nextLocation) => {
if (!confirmedNavigation &&
nextLocation.location.pathname !== location.pathname) {
setShowPrompt(true);
setLastLocation(nextLocation);
return false;
}
return true;
}, [confirmedNavigation]);
const confirmNavigation = useCallback(() => {
setShowPrompt(false);
setConfirmedNavigation(true);
}, []);
useEffect(() => {
if (confirmedNavigation && lastLocation) {
navigate(lastLocation.location.pathname);
}
}, [confirmedNavigation, lastLocation]);
useBlocker(handleBlockedNavigation, when);
return [showPrompt, confirmNavigation, cancelNavigation];
}
export default useCallbackPrompt
Run Code Online (Sandbox Code Playgroud)
以上是我正在使用的两个文件。在 useBlocker.js 文件中,该特定行实际上导致了根本问题。请参考下图
我正在使用"react-router-dom": "^6.3.0",这会引起任何问题吗?任何建议或修改都将受到高度赞赏。
我无法使用 重现该问题react-router-dom@6.3.0,但当遇到react-router-dom@6.4.0. 我怀疑指定了依赖项,因为^6.3.0您实际上已经安装了更新的版本。如果您愿意,可以通过运行来检查已安装的版本npm list react-router-dom并自行验证。
v6.3.0 和 v6.4.0 之间的导航上下文似乎有轻微的破坏性变化。v6.3.0 版本是历史对象(source),而 v6.4.0 是新的导航上下文对象,其中navigator界面更简单(source)。
6.3.0您可以通过运行npm i -s react-router-dom@6.3.0安装该确切版本来恢复到原来的状态。仔细检查您的 package.json 文件以确保条目为"react-router-dom": "6.3.0"。
history对象如果您想继续使用较新的 RRD 版本,那么我建议的另一种选择是history@5 history直接使用该对象,而不是尝试使用react-router@6 navigator. 无论如何,RRDv6 只导出history方法的子集。
添加history@5为项目依赖项。
重要提示:您需要检查react-router-dom正在使用的版本并匹配(如果可以的话)。
创建并导出自定义历史对象。createBrowserHistory对于 BrowserRouter、createHashHistory对于 HashRouter 等。
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;
Run Code Online (Sandbox Code Playgroud)
从 RRD 导入您的自定义历史对象和历史路由器。
import { unstable_HistoryRouter as Router } from "react-router-dom";
import history from './history';
...
<Router history={history}>
<App />
</Router>
Run Code Online (Sandbox Code Playgroud)
导入您的自定义历史对象以在自定义挂钩中使用。
import { useCallback, useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import history from "./history"; // <-- import
const useBlocker = (blocker, when = true) => {
useEffect(() => {
if (!when) return;
const unblock = history.block((tx) => { // <-- use history
const autoUnblockingTx = {
...tx,
retry() {
unblock();
tx.retry();
}
};
blocker(autoUnblockingTx);
});
return unblock;
}, [blocker, when]);
};
Run Code Online (Sandbox Code Playgroud)
useCallbackPrompt未受影响。
const useCallbackPrompt = (when) => {
const navigate = useNavigate();
const location = useLocation();
const [showPrompt, setShowPrompt] = useState(false);
const [lastLocation, setLastLocation] = useState(null);
const [confirmedNavigation, setConfirmedNavigation] = useState(false);
const cancelNavigation = useCallback(() => {
setShowPrompt(false);
}, []);
const handleBlockedNavigation = useCallback(
(nextLocation) => {
if (
!confirmedNavigation &&
nextLocation.location.pathname !== location.pathname
) {
setShowPrompt(true);
setLastLocation(nextLocation);
return false;
}
return true;
},
[confirmedNavigation]
);
const confirmNavigation = useCallback(() => {
setShowPrompt(false);
setConfirmedNavigation(true);
}, []);
useEffect(() => {
if (confirmedNavigation && lastLocation) {
navigate(lastLocation.location.pathname);
}
}, [confirmedNavigation, lastLocation]);
useBlocker(handleBlockedNavigation, when);
return [showPrompt, confirmNavigation, cancelNavigation];
};
Run Code Online (Sandbox Code Playgroud)
演示
从 v6.4.0 开始,navigator.block 被删除。您可以在这里找到解决方法:https://gist.github.com/MarksCode/64e438c82b0b2a1161e01c88ca0d0355。
另外,相关讨论也正在进行中。https://github.com/remix-run/react-router/issues/8139#issuecomment-1262630360
| 归档时间: |
|
| 查看次数: |
8739 次 |
| 最近记录: |