В моем приложении есть две страницы: Step1 и Step2. Step1 имеет флажок, который блокирует навигацию, если он установлен, и кнопку Next, которая при нажатии переходит к Step2. Step2 имеет кнопку Previous, при нажатии на которую осуществляется переход обратно к Step1.

Ссылка на демо

.

В соответствии с этим учебником, я использую метод block объекта createBrowserHistory для блокировки изменений маршрута, если установлен флажок в Step1:

const unblock = useRef();

  useEffect(() => {
    unblock.current = history.block((tx) => {
      if (block.current.checked) {
        const promptMessage = "Are you sure you want to leave?";

        if (window.confirm(promptMessage)) {
          unblock.current();
          tx.retry();
        }
      } else {
        console.log("tfgx");
        unblock.current();
        tx.retry();
      }
    });
  }, []);

Мне также пришлось установить свойство history в низкоуровневом (не ) в объект createBrowserHistory, как показано ниже:


...

Но это мешает правильному отображению маршрутов. Я думаю, что это может быть связано с тем, что не может правильно прочитать объект местоположения. Если я использую , объект местоположения выглядит следующим образом: {pathname: "/step1", ... key: "7sd45"}. Но когда я использую , объект местоположения выглядит следующим образом {action: "PUSH", location: {pathname: "/step1", ... key: "7sd45"}}. (Я также получаю предупреждение Вы не можете изменить <историю маршрутизатора>.)

Моим желаемым результатом является блокирование навигации, если установлен флажок "Блокировать навигацию", и разблокирование в противном случае. Если местоположение меняется, когда навигация разблокирована, я хотел бы, чтобы соответствующий маршрут отображался правильно.

.

Раздел о createBrowserHisory в документации по React Router v5 скуден, а примеров, использующих его, не так много, поэтому я буду благодарен, если кто-нибудь прольет свет на этот вопрос.


EDIT: Передача location.location в , кажется, исправляет это (обновленная демонстрация). Но если я вызову useLocation внутри Step1 и выведу результат (строки 17-18), я получу {pathname: "/step1", ... key: "7sd45"}, а не {action: "PUSH", location: {pathname: "/step1", ... key: "7sd45"}}. Почему так?

Также, если пользователь пытается перейти в другое место, когда навигация заблокирована, моя пользовательская подсказка появляется, как и ожидалось ("Вы уверены, что хотите уйти" с кнопками "OK" и "Отмена"). Однако если пользователь отклоняет это предложение, нажимая кнопку "Отмена", появляется собственное диалоговое окно браузера -

В Chrome:

введите описание изображения здесь

В Firefox:

введите описание изображения здесь

Возможно ли подавить подсказку браузера после того, как моя подсказка была отклонена?

Ответы (1)

Объект history контекста маршрутизатора также имеет функцию блока, но работает она немного иначе. Она принимает обратный вызов, который потребляет аргументы location и action.

history.block((location, action) => {...});

Возврат false из обратного вызова блокирует переход навигации, возврат true позволяет перейти.

React.useEffect(() => {
  const unblock = history.block((location, action) => {
    if (checkBlockingCondition) {
      return window.confirm("Navigate Back?");
    }
    return true;
  });

  return () => {
    unblock();
  };
}, []);

В качестве альтернативы react-router-dom предлагает использовать компонент Prompt для условного блокирования переходов маршрута. Ваш код очень близок к их предотвращающему переходы примеру.

Обновления к вашему последнему codesandbox:

  1. Используйте блокирующее состояние в сравнении с реактивным рефлексом, чтобы подсказка возвращалась и заново оценивала условие.
  2. Рендеринг компонента Prompt.
  3. Предотвращение стандартного действия отправки формы, т. е. предотвращение перезагрузки страницы.

код

import {
  BrowserRouter as Router,
  Prompt, // <-- import Prompt
  Redirect,
  Switch,
  Route,
  useLocation
} from "react-router-dom";

const Step1 = ({ id, history }) => {
  const [isBlocking, setIsBlocking] = useState(false);

  return (
    
{ e.preventDefault(); // <-- prevent default form action, i.e. page reload history.push("/step2"); }} >

); };

Edit react-router-v5-2-blocking-route-change-with-createbrowserhistory-and-history

2022 WebDevInsider