You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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

火山引擎 最新活动