我想使用 React hook 创建自定义历史记录后退和前进按钮。
作为参考,如果有帮助的话,我正在尝试复制 Spotify 网络应用程序中可以看到的行为。他们的自定义前进和后退按钮与浏览器历史记录按钮无缝集成。
我认为我的功能大部分都可以工作,但有一个问题。这是我的 React 钩子:
import { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
const useNavigationHistory = () => {
const history = useHistory();
const [length, setLength] = useState(0);
const [direction, setDirection] = useState(null);
const [historyStack, setHistoryStack] = useState([]);
const [futureStack, setFutureStack] = useState([]);
const canGoBack = historyStack.length > 0;
const canGoForward = futureStack.length > 0;
const goBack = () => {
if (canGoBack) {
history.goBack();
}
};
const goForward = () => {
if (canGoForward) {
history.goForward();
}
};
useEffect(() => {
return history.listen((location, action) => {
// if action is PUSH we are going forwards
if (action === 'PUSH') {
setDirection('forwards');
setLength(length + 1);
// add the new location to the historyStack
setHistoryStack([...historyStack, location.pathname]);
// clear the futureStack because it is not possible to go forward from here
setFutureStack([]);
}
// if action is POP we could be going forwards or backwards
else if (action === 'POP') {
// determine if we are going forwards or backwards
if (futureStack.length > 0 && futureStack[futureStack.length - 1] === location.pathname) {
setDirection('forwards');
// if we are going forwards, pop the futureStack and push it onto the historyStack
setHistoryStack([...historyStack, futureStack.pop()]);
setFutureStack(futureStack);
} else {
setDirection('backwards');
// if we are going backwards, pop the historyStack and push it onto the futureStack
setFutureStack([...futureStack, historyStack.pop()]);
setHistoryStack(historyStack);
}
setLength(historyStack.length);
}
});
}, [history, length, historyStack, futureStack]);
return { canGoBack, canGoForward, goBack, goForward };
};
export default useNavigationHistory;
在我的测试中,在各个不同页面之间前后导航时,这一切似乎都工作正常。
如果我通过在相同的两页之间交替向前导航,例如:
/home
/about
/home
/about
/home
/about
...然后我判断我们是前进还是后退的逻辑就崩溃了。
我认为是这一行:
if (futureStack.length > 0 && futureStack[futureStack.length - 1] === location.pathname) {
因为向前路径名和向后路径名是相同的,所以即使我向后走,它也认为我正在向前走。
我一直在试图找出如何解决这个问题,但还没有成功。
有人可以帮忙吗?
也许我的解决方案有缺陷,我需要一种完全不同的方法,我不确定。
事实证明,react-router-dom 的 useHistory hook 返回的数据已经包含历史记录中每个项目的唯一键值。
因此,解决方案就是简单地将钩子中
location.pathname
的每个实例交换为 location.key
,现在它的行为符合预期。