使用React Hook实现自定义历史前进后退按钮的问题求助
使用React Hook实现自定义历史前进后退按钮的问题求助
我想要用React Hook做一套自定义的页面前进后退按钮,目标是复刻Spotify网页版的那种体验——自定义按钮和浏览器自带的历史按钮能完全同步,无缝配合。
目前我差不多把功能搭起来了,但碰到一个棘手的问题,先把我的Hook代码贴出来:
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) {
因为这时候前进和后退的路径名完全一样,哪怕我是在点后退按钮,代码也会误以为我是在前进。
我自己折腾了好一阵都没解决,有没有大佬能给点思路?说不定我的整个实现思路就有问题,需要换个方向也说不定。
备注:内容来源于stack exchange,提问作者Alex




