浏览器后退按钮无限循环中的确认模式

问题描述 投票:0回答:1

我正在尝试实现一个确认模式,当用户尝试导航离开未保存更改的页面时会出现该模式。当单击浏览器的后退按钮或页面上的“上一个”按钮时,模式会正确显示,但是当我确认操作时,模式会进入无限循环,不断再次打开而不是导航离开。此问题仅出现在后退按钮或“上一页”按钮上;通过其他链接导航时,一切都按预期进行。

当点击触发导航到特定路径(例如,从标题链接)的链接或按钮时,模式工作正常,但当确认由浏览器的后退按钮或浏览器中的“上一个”按钮触发的导航时,模式会进入无限循环。形式。

如果没有 window.history.pushState(null, '', location.pathname + location.search);,模态框根本不会出现在后退导航上,但是有了它,模态框在尝试时会不断地在无限循环中重新出现。确认返回导航。

如何防止模态进入无限循环并在用户确认后退导航时正确导航离开?

`const EstimateRequestPage = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const params = new URLSearchParams(location.search);

  const [isModalOpen, setIsModalOpen] = useState(false);
  const { isDirty, setIsDirty } = useIsDirty();

  const { handleNavigate, renderModal } = usePreventLeave(isDirty);

  return (
    <Container>
      <form onSubmit={handleSubmit}>
        {/* Form fields... */}
        <ButtonGroup>
          <PreviousButton variant="outlined" onClick={() => handleNavigate(-1)}>
            Previous
          </PreviousButton>
          <RequestButton variant="contained" type="submit">
            Submit
          </RequestButton>
        </ButtonGroup>
      </form>
      {renderModal()}
    </Container>
  );
};`



`import { useState, useCallback, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import ConfirmationModal from '@/components/ui/modal/Modal';

export const usePreventLeave = (isDirty) => {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [pendingPath, setPendingPath] = useState(null);
  const navigate = useNavigate();
  const location = useLocation();

  useEffect(() => {
    const handlePopState = (event) => {
      if (isDirty) {
        window.history.pushState(null, '', location.pathname + location.search);
        setIsModalOpen(true);
      }
    };
    window.history.pushState(null, '', location.pathname + location.search);
    window.addEventListener('popstate', handlePopState);

    return () => {
      window.removeEventListener('popstate', handlePopState);
    };
  }, [isDirty, location.pathname, location.search]);

  const handleNavigate = useCallback(
    (path) => {
      if (isDirty) {
        setPendingPath(path);
        setIsModalOpen(true); // Show modal
      } else {
        navigate(path); // Navigate if not dirty
      }
    },
    [isDirty, navigate]
  );

  const handleConfirm = useCallback(() => {
    setIsModalOpen(false);
    if (pendingPath === null) {
      navigate(-1); // Back navigation
    } else if (pendingPath) {
      navigate(pendingPath); // Navigate to pending path
    }
    setPendingPath(null);
  }, [navigate, pendingPath]);

  const handleCancel = useCallback(() => {
    setIsModalOpen(false);
    setPendingPath(null); // Reset state
  }, []);

  return {
    handleNavigate,
    renderModal: () => (
      <ConfirmationModal
        open={isModalOpen}
        handleClose={handleCancel}
        handleConfirm={handleConfirm}
        messageId1="Leave page?"
        messageId2="Unsaved changes will be lost."
        confirmButtonId="confirm_button"
      />
    ),
    setPendingPath,
  };
};
`
reactjs routes popstate
1个回答
0
投票

问题是,当您确认导航时,handleNavigate函数可能会触发状态更改,导致handlePopState再次运行,从而导致无限循环。尝试下面的代码,我提供了使用 event.preventDefault() 代替 window.history.pushState() ,并在组件卸载后添加事件侦听器并删除事件侦听器,并从 useeffect 依赖项数组中删除 location.pathname 和 location.search 。

useEffect(() => {
    const handlePopState = (event) => {
      if (isDirty) {
        // Prevent the default behavior and show the modal
        event.preventDefault();
        setIsModalOpen(true);
      }
    };

    // Adding event listener for popstate
    window.addEventListener('popstate', handlePopState);

    // Clean up the event listener on component unmount
    return () => {
      window.removeEventListener('popstate', handlePopState);
    };
  }, [isDirty]);

© www.soinside.com 2019 - 2024. All rights reserved.