Предупреждать пользователя перед тем, как покинуть страницу после ввода некоторых данных (особенно в ReactJS)

Я создаю страницу, на которой пользователю необходимо ввести данные, чтобы добавить продукт в список продуктов. Если пользователь случайно уходит с этой страницы после ввода некоторых данных в форму, перед уходом от пользователя должно быть обязательное подтверждение. Но я борюсь с этим требованием. Я использую react-hook-form для хранения данных на сервере JSON.

Я использую состояние leave, если оно верно, то предупредите пользователя, прежде чем выйти, иначе ничего.

const [leave, setLeave] = useState(false);

Теперь я не знаю, где и как использовать это состояние для отображения окна предупреждения перед уходом. Вот моя форма, которая будет рендерить.

render (
<Form onSubmit={handleSubmit(onSubmit)}>
   <Form.Row>
       <Form.Group as={Col} className="mr-5">
       <Form.Label column>Product Name</Form.Label>
       <Form.Control
            name="productName"
            placeholder="Enter product Name"
            required
            ref={register}
            />
       </Form.Group>
   </Form.Row>
   <Button variant="success" type="submit" className="text-white mt-5">
            Add New Product
   </Button>
</Form>

<Prompt when={Leave} message="Are you sure you want to leave ?" /> {/*Here I have promted*/}
);

Для простоты я дал только одно поле ввода. Теперь определение функции onSubmit приведено ниже.

const onSubmit = (formData) => {
    setLeave(true);   //here I am setting this true
    axios.post("http://localhost:4000/products", formData);
    navigation.push({
        pathname: "/productList",
        state: { added: "pass" },
      });
};

Это будет работать при отправке формы, но я хочу получать запрос, когда пользователь нажимает кнопку "Назад" или любую навигационную ссылку.


person Subrato Patnaik    schedule 15.10.2020    source источник
comment
Проверьте обработчик событий onbeforeunload. Вопрос аналогичного типа (хотя и не конкретный) находится здесь: stackoverflow.com/questions/1119289/   -  person veddermatic    schedule 15.10.2020


Ответы (3)


when должно быть истинным, если вы хотите прервать навигацию.

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

Переверните его на true, когда в значения формы будет внесено первое изменение. Может быть просто useEffect с formData в качестве зависимости? Убедитесь, что он еще не перевернут, чтобы предотвратить ненужные рендеры.

Верните его обратно в false, когда вы получите 200 от своего представления, чтобы разрешить последующую навигацию.

Я не думаю, что React будет повторно отображать до того, как подсказка будет запущена в вашем текущем onSubmit, поэтому вам может потребоваться найти способ навигации после проверки отправки.

Другой флаг, такой как didSubmit, позволит вам отобразить путь кода для рендеринга <Redirect> вместо вызова navigation.push(), если это подходит.

Но в противном случае, используя ваши текущие настройки, вы можете разрешить навигацию, когда вы попадете на новую форму (ваш пользователь еще не приложил никаких усилий), навигация будет прервана, если форма «грязная», и навигация будет происходить автоматически на следующий рендер после установки didSubmit.

const [isDirty, setIsDirty] = React.useState(false)
const [didSubmit, setDidSubmit] = React.useState(false)
const onSubmit = async (formData) => {
  try {
    await axios.post('url', formData)
    setIsDirty(false)
    setDidSubmit(true)
  } catch (error) {
    // handle your errors
  }
}
React.useEffect(() => {
  if(!isDirty) setIsDirty(true)
}, [formData])
React.useEffect(() => {
  if(didSubmit) navigation.push({ ... })
}, [didSubmit]

return (
  // the form...
  <Prompt when={isDirty} {...} />
)
person Lynden Noye    schedule 15.10.2020
comment
если formdata имеет значение null, он не будет запрашивать. Как я могу этого добиться? Это возможно? - person Subrato Patnaik; 15.10.2020
comment
и если formdata является объектом, то он также не должен запрашиваться. - person Subrato Patnaik; 15.10.2020
comment
вы можете добавить любые условия к useEffect, где мы установили isDirty. Например, if (!isDirty || !formData || typeof formData === 'object') setIsDirty(true). Хотя я не уверен, почему, если пользователь не ввел никаких данных, вы хотите, чтобы они были прерваны, пытаясь перейти куда-то еще. Не могли бы вы уточнить, почему? - person Lynden Noye; 15.10.2020

Я обновил состояние isDirty или leave до истинного при изменении поля ввода формы, как показано ниже.

render (
<Form onSubmit={handleSubmit(onSubmit)}>
   <Form.Row>
       <Form.Group as={Col} className="mr-5">
       <Form.Label column>Product Name</Form.Label>
       <Form.Control
            name="productName"
            placeholder="Enter product Name"
            required
            onChange={() => setIsDirty(true)} {/* I have updated here*/}
            ref={register}
            />
       </Form.Group>
   </Form.Row>
   <Button variant="success" type="submit" className="text-white mt-5">
            Add New Product
   </Button>
</Form>

<Prompt when={isDirty} message="Are you sure you want to leave ?" /> 
);

Теперь внутри функции onSubmit я обновил состояние isDirty до false перед переходом к месту назначения.

const onSubmit = (formData) => {
    axios.post("http://localhost:4000/products", formData);
    setIsDirty(false);   //here I am setting this true
    navigation.push({
        pathname: "/productList",
        state: { added: "pass" },
      });
};

Я хотел бы поделиться здесь важным моментом: всякий раз, когда происходит изменение ввода в любой момент, только состояние isDirty становится true, а во время отправки формы (все поля ввода заполнены) состояние изменяется на false, чтобы он мог перемещаться на другой URL.

person Subrato Patnaik    schedule 15.10.2020
comment
@Lynden Noye Некоторые кредиты ему. Я смог решить свою проблему с его ответом. - person Subrato Patnaik; 01.11.2020

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

useEffect(() => {
  return () => {
       // you can add your functionality here  
   };
 }, []);
person Kodali444    schedule 17.04.2021