Как предотвратить потерю данных формы перед выходом со страницы?
Как предотвратить потерю данных формы перед выходом со страницы?

Приходите и попробуйте ChatGpt бесплатно Плюс версия, мы платим за это 体验地址:https://chat.waixingyun.cn Вы можете присоединиться к технической группе внизу сайта и вместе находить ошибки.

В этой статье описывается, как реализовать компонент FormPrompt, который предупреждает пользователей, когда они пытаются уйти со страницы с несохраненными изменениями. В статье обсуждается, как справляться с подобными ситуациями, используя чистый JavaScript и событие beforeunload, а также решения, специфичные для React, такие как использование компонента Prompt в React Router v5, useBeforeUnload и нестабильность. Хорошей практикой взаимодействия с пользователем является добавление к пользователю диалогового окна подтверждения с просьбой подтвердить перенаправление, если у него есть несохраненные изменения формы. Отображая это приглашение, пользователи будут знать, что у них есть несохраненные изменения, и им будет разрешено сохранить или отменить свою работу, прежде чем продолжить перенаправление.

Ниже текст~

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

В этой статье будет показано, как реализовать FormPrompt Компонент, который предупреждает пользователей, когда они пытаются уйти со страницы с несохраненными изменениями, эффективно улучшая общий пользовательский опыт. Мы обсудим, как использовать чистый JavaScript Чтобы справиться с такими ситуациями, используйте React Router v5 в Prompt компоненты, а также в React Router v6 используется в useBeforeUnload и unstable_useBlocker Зацепить конкретное решение.

Финальную версию приложения можно найти по адресу CodeSandbox Протестировано, код можно найти по адресу GitHub получено дальше.

Используйте событие beforeunload, чтобы определить, когда страница уходит.

мы создаем FormPrompt компонент, в который нужно добавить beforeunload Слушатель событий. Это событие будет запущено до того, как пользователь покинет страницу. Позвонив на мероприятие preventDefault Метод, мы можем вызвать диалоговое окно подтверждения браузера. Только если в форме есть несохраненные изменения (по hasUnsavedChanges указывает свойство), это диалоговое окно будет активировано.

Язык кода:javascript
копировать
// FormPrompt.js

import { useEffect } from "react";

export const FormPrompt = ({ hasUnsavedChanges }) => {
  useEffect(() => {
    const onBeforeUnload = (e) => {
      if (hasUnsavedChanges) {
        e.preventDefault();
        e.returnValue = "";
      }
    };
    window.addEventListener("beforeunload", onBeforeUnload);
    return () => {
      window.removeEventListener("beforeunload", onBeforeUnload);
    };
  }, [hasUnsavedChanges]);
};

В качестве примера мы будем использовать Contact шагиспользуется в Этот компонент:

Язык кода:javascript
копировать
// Steps/Contact.js

import { forwardRef } from "react";
import { useForm } from "react-hook-form";
import { useAppState } from "../state";
import { Button, Field, Form, Input } from "../Forms";
import { FormPrompt } from "../FormPrompt";

export const Contact = forwardRef((props, ref) => {
  const [state, setState] = useAppState();
  const {
    handleSubmit,
    register,
    formState: { isDirty },
  } = useForm({
    defaultValues: state,
    mode: "onSubmit",
  });

  const saveData = (data) => {
    setState({ ...state, ...data });
  };

  return (
    <Form onSubmit={handleSubmit(saveData)} nextStep={"/education"}>
      <FormPrompt hasUnsavedChanges={isDirty} />
      <fieldset>
        <legend>Contact</legend>
        <Field label="First name">
          <Input {...register("firstName")} id="first-name" />
        </Field>
        <Field label="Last name">
          <Input {...register("lastName")} id="last-name" />
        </Field>
        <Field label="Email">
          <Input {...register("email")} type="email" id="email" />
        </Field>
        <Field label="Password">
          <Input {...register("password")} type="password" id="password" />
        </Field>
        <Button ref={ref}>Next {">"}</Button>
      </fieldset>
    </Form>
  );
});

При вводе данных в поле формы и попытке перезагрузить страницу или перейти по внешнему URL-адресу перед сохранением изменений браузер отобразит диалоговое окно подтверждения.

Запретить навигацию по страницам с помощью React Router 5

Этот компонент достаточно хорош для нашего приложения, поскольку все его страницы являются частью формы. Однако в реальных ситуациях это не всегда так. Чтобы сделать наш пример более репрезентативным, мы добавим Home Новый маршрут, который будет перенаправляться за пределы формы. Home Компонент очень простой и отображает только приветствие домашней страницы.

Язык кода:javascript
копировать
// Home.js

export const Home = () => {
  return <div>Welcome to the home page!</div>;
};

Нам также необходимо внести некоторые изменения в компонент приложения, чтобы он соответствовал этому новому маршруту.

Язык кода:javascript
копировать
// App.js

import { useRef } from "react";
import {
  BrowserRouter as Router,
  Routes,
  Route,
  NavLink,
} from "react-router-dom";
import { AppProvider } from "./state";
import { Contact } from "./Steps/Contact";
import { Education } from "./Steps/Education";
import { About } from "./Steps/About";
import { Confirm } from "./Steps/Confirm";
import { Stepper } from "./Steps/Stepper";
import { Home } from "./Home";

export const App = () => {
  const buttonRef = useRef();

  const onStepChange = () => {
    buttonRef.current?.click();
  };

  return (
    <div className="App">
      <AppProvider>
        <Router>
          <div className="nav-wrapper">
            <NavLink to={"/"}>Home</NavLink>
            <Stepper onStepChange={onStepChange} />
          </div>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/contact" element={<Contact ref={buttonRef} />} />
            <Route path="/education" element={<Education ref={buttonRef} />} />
            <Route path="/about" element={<About ref={buttonRef} />} />
            <Route path="/confirm" element={<Confirm />} />
          </Routes>
        </Router>
      </AppProvider>
    </div>
  );
};

Мы видим, что когда мы вводим информацию в форму и переходим на домашнюю страницу, введенные данные не сохраняются и диалоговое окно подтверждения не появляется. Это связано с тем, что навигация обрабатывается React. Обработка маршрутизатора не срабатывает beforeunload событие, в результате чего API браузера в этом случае становится недействительным. К счастью, Реакт Router v5 обеспечивает Prompt компоненты,предупреждать пользователей перед тем, как покинуть страницу с несохраненными изменениями。该компоненты接受两个propswhen и messagewhen Свойство — это логическое значение, которое определяет, должно ли отображаться приглашение, а message Свойства представляют собой текст, отображаемый пользователю.

При использовании подсказки поведение корректно при переходе к домашнему маршруту, но когда пользователь вводит данные формы и переходит к следующему шагу, также появляется диалоговое окно подтверждения. Это нежелательно, поскольку мы сохраняем данные формы при переходе к следующему шагу.

Для решения этой задачи нам необходимо проверить следующее URL Это один из шагов формы перед проверкой несохраненных изменений. Можно использовать message Свойство для достижения этой цели также может быть функцией. Первый параметр этой функции — следующая позиция. Если функция возвращает true , то переход к следующему разрешен URL; в противном случае он может вернуть строку для отображения приглашения.

Язык кода:javascript
копировать
// FormPrompt.js

import { useEffect } from "react";
import { Prompt } from "react-router-dom";

const stepLinks = ["/contact", "/education", "/about", "/confirm"];

export const FormPrompt = ({ hasUnsavedChanges }) => {
  useEffect(() => {
    const onBeforeUnload = (e) => {
      if (hasUnsavedChanges) {
        e.preventDefault();
        e.returnValue = "";
      }
    };
    window.addEventListener("beforeunload", onBeforeUnload);

    return () => {
      window.removeEventListener("beforeunload", onBeforeUnload);
    };
  }, [hasUnsavedChanges]);

  const onLocationChange = (location) => {
    if (stepLinks.includes(location.pathname)) {
      return true;
    }
    return "You have unsaved changes, are you sure you want to leave?";
  };

  return <Prompt when={hasUnsavedChanges} message={onLocationChange} />;
};

Благодаря этим изменениям мы можем безопасно перемещаться между этапами формы и получать предупреждения при попытке выйти из формы без сохраненных изменений.

Запретить навигацию по страницам с помощью React Router 6

элементы были удалены и unstable_usePrompt Крючок 6.7.0 версия добавлена. Как следует из названия, реализация перехватчика может быть изменена и еще не документирована. Однако для нашего варианта использования это должно работать.

Мы можем использовать этот крючок для репликации версии 5. Prompt поведение компонента, но сначала нам нужно настроить наш App компоненты для использования нового маршрутизатора данных в том виде, в котором они есть. unstable_usePrompt Это необходимо для работы крючка.

Язык кода:javascript
копировать
// App.js

import { useRef } from "react";
import { createBrowserRouter, RouterProvider, Outlet } from "react-router-dom";
import { AppProvider } from "./state";
import { Contact } from "./Steps/Contact";
import { Education } from "./Steps/Education";
import { About } from "./Steps/About";
import { Confirm } from "./Steps/Confirm";
import { Stepper } from "./Steps/Stepper";
import { Home } from "./Home";

export const App = () => {
  const buttonRef = useRef();

  const onStepChange = () => {
    buttonRef.current?.click();
  };

  const router = createBrowserRouter([
    {
      element: (
        <>
          <Stepper onStepChange={onStepChange} />
          <Outlet />
        </>
      ),
      children: [
        {
          path: "/",
          element: <Home />,
        },
        {
          path: "/contact",
          element: <Contact ref={buttonRef} />,
        },
        { path: "/education", element: <Education ref={buttonRef} /> },
        { path: "/about", element: <About ref={buttonRef} /> },
        { path: "/confirm", element: <Confirm /> },
      ],
    },
  ]);

  return (
    <div className="App">
      <AppProvider>
        <RouterProvider router={router} />
      </AppProvider>
    </div>
  );
};

мы используем createBrowserRouter функция для создания маршрутизатора. Обратите внимание, что Stepper Отдельного пути нет, все остальные маршруты являются его дочерними маршрутами. Он действует как компонент макета и отображается на каждой странице. Содержимое каждой страницы отображается в специальном Outlet Расположение компонента. Чтобы упростить App Logic, мы также перемещаем ссылку навигации по домашней странице в Stepper середина.

После завершения настройки мы можем реализовать функцию блокировки перенаправления. Сначала мы проходим FormPrompt используется Введено в версии 6.6 useBeforeUnload крючок на замену onbeforeunload логика.

Язык кода:javascript
копировать
// FormPrompt.js

import { useEffect, useCallback, useRef } from "react";
import { useBeforeUnload } from "react-router-dom";

const stepLinks = ["/contact", "/education", "/about", "/confirm"];

export const FormPrompt = ({ hasUnsavedChanges }) => {
  useBeforeUnload(
    useCallback(
      (event) => {
        if (hasUnsavedChanges) {
          event.preventDefault();
          event.returnValue = "";
        }
      },
      [hasUnsavedChanges]
    ),
    { capture: true }
  );

  return null;
};

Это изменение упрощает внешний вид нашего компонента. Теперь мы можем добавить пользовательский. usePrompt крючки и лайк версии 5в Prompt Используйте его как компонент.

Язык кода:javascript
копировать
// FormPrompt.js

import { useEffect, useCallback, useRef } from "react";
import {
  useBeforeUnload,
  unstable_useBlocker as useBlocker,
} from "react-router-dom";

const stepLinks = ["/contact", "/education", "/about", "/confirm"];

export const FormPrompt = ({ hasUnsavedChanges }) => {
  const onLocationChange = useCallback(
    ({ nextLocation }) => {
      if (!stepLinks.includes(nextLocation.pathname) && hasUnsavedChanges) {
        return !window.confirm(
          "You have unsaved changes, are you sure you want to leave?"
        );
      }
      return false;
    },
    [hasUnsavedChanges]
  );

  usePrompt(onLocationChange, hasUnsavedChanges);
  useBeforeUnload(
    useCallback(
      (event) => {
        if (hasUnsavedChanges) {
          event.preventDefault();
          event.returnValue = "";
        }
      },
      [hasUnsavedChanges]
    ),
    { capture: true }
  );

  return null;
};

function usePrompt(onLocationChange, hasUnsavedChanges) {
  const blocker = useBlocker(hasUnsavedChanges ? onLocationChange : false);
  const prevState = useRef(blocker.state);

  useEffect(() => {
    if (blocker.state === "blocked") {
      blocker.reset();
    }
    prevState.current = blocker.state;
  }, [blocker]);
}

useBlocker Хук принимает в качестве аргумента логическую или блокирующую функцию, что-то вроде Prompt Компоненты message свойство. Одним из параметров функции является следующая позиция, мы UseIt определяет, покидает ли пользователь нашу форму. В этом случае мы используем функцию браузера window.confirm Метод отображает диалоговое окно с просьбой подтвердить перенаправление или отменить его. Наконец, мы usePrompt Логика блокировки абстрагируется в перехватчике, и состояние блокировщика управляется.

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

Подвести итог

Таким образом, внедрение диалоговых окон подтверждения для несохраненных изменений формы является важной практикой для улучшения пользовательского опыта. В этой статье показано, как создать FormPrompt Компонент, предупреждающий пользователей, когда они пытаются уйти со страницы с несохраненными изменениями. Мы рассмотрели, как справиться с этой ситуацией, используя чистый JavaScript, используя beforeunload событиеи вReactиспользуется вReact Router v5в Prompt Компоненты и React Router v6в useBeforeUnload и unstable_useBlocker крюк. Включив эту функцию в свои формы, вы можете помочь пользователям избежать разочарования, связанного с потерей несохраненной работы.

Невозможно узнать возможные ошибки в реальном времени после развертывания кода. Чтобы впоследствии устранить эти ошибки, на логирование уходит много времени. Для отладки я хотел бы порекомендовать вам полезный инструмент для мониторинга ошибок. Fundebug

оригинальный:https://claritydev.net/blog/display-warning-for-unsaved-form-...

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose