Как исправить это нежелательное поведение кнопок в ReactJS?

Я пытаюсь условно переключаться между двумя кнопками HTML в ReactJS в зависимости от того, отображается форма или нет. По сути, если форма отображается, покажите кнопку отправки, а если она не отображается, покажите обычную кнопку для отображения формы.

Это код, который у меня есть. (Я использую компонент кнопки Antd, но я также пробовал использовать обычную кнопку HTML и столкнулся с той же проблемой.

<div>
        {showForm ? (
          <Button
            loading = {isUploading}
            htmlType = "submit"
            form = "videoForm"
            className = {Styles.button}
          >
            {isUploading ? 'Uploading' : 'Upload Video'}
          </Button>
        ) : (
          <Button
            htmlType = "button"
            onClick = {() => setShowForm(true)}
            className = {Styles.button}
          >
            {successMsg ? 'Upload Another Video' : 'Show Form'}
          </Button>
        )}
      </div>

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

Есть идеи, почему? И как я могу решить эту проблему? Я также попробовал сделать следующее, но получил те же результаты.

<div>
        <Button
          loading = {isUploading}
          htmlType = {showForm ? 'submit' : 'button'}
          form = "videoForm"
          className = {Styles.button}
        >
          {showForm && (isUploading ? 'Uploading' : 'Upload Video')}
          {!showForm && (successMsg ? 'Upload Another Video' : 'Show Form')}
        </Button>
      </div>

Любая помощь будет принята с благодарностью.

Помните, что по умолчанию type из button элементов — submit. Попробуйте добавить type = "button" к обычной кнопке.

Robo Robok 05.05.2024 04:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
53
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

попробуй поставить setShowForm в setTimeout

<button onClick = {() => setTimeout(() => setShowForm(true))}>...</button>

Кнопки внутри формы всегда действуют как кнопка отправки. Вы можете предотвратить это, добавив дополнительную функцию для события onClick и PreventDefault(), когда тип кнопки — «кнопка».

Ответ принят как подходящий

Это поведение не связано со значением type по умолчанию для <button>, поскольку OP уже устанавливает <button> базового HTML-элемента type на 'button' через опору htmlType. Это поведение также можно воспроизвести без React, как показано ниже:

const form = document.getElementById('form'),
  btnWo = document.getElementById('btn-wo'),
  btnW = document.getElementById('btn-w');

form.onsubmit = function (event) {
  console.info('form onsubmit');
  event.preventDefault();
}

btnWo.onclick = function (event) {
  console.info(`btn-wo onclick, type = ${this.type}`);
}

btnW.onclick = function (event) {
  console.info(`btn-w onclick, type = ${this.type}`);
  this.type = 'submit';
}
<form id = "form">
  <button id = "btn-wo" type = "button">Button without Changing Type</button>
  <button id = "btn-w" type = "button">Button with Changing Type</button>
</form>

При нажатии «Кнопки с изменяющимся типом» ее type меняется на 'submit' в обработчике событий. После того, как обработчик события возвращается, форма отправляется, потому что нажатый <button>type теперь 'submit'.

То же самое происходит и в примере OP, поскольку React не перемонтирует компонент <Button> (и базовый HTML-элемент <button>), изменяется только свойство htmlType (и свойство type базового элемента).

Чтобы это исправить, либо:

  1. Вызовите preventDefault() внутри прослушивателя событий. Это предотвратит действие по умолчанию — нажатие кнопки отправки <button>, связанное с формой, которая отправляет форму.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.info("form onSubmit");
    event.preventDefault();
    setShowForm(false);
  };

  return (
    <div>
      <div>
        {showForm ? (
          <button type = "submit" form = "videoForm">
            Upload Video
          </button>
        ) : (
          <button
            type = "button"
            onClick = {(event) => {
              setShowForm(true);
              event.preventDefault();
            }}
          >
            Show Form
          </button>
        )}
        {showForm && (
          <form id = "videoForm" onSubmit = {onSubmit}>
            <input />
          </form>
        )}
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
  1. Измените <button> на type после таймаута. Это работает, потому что 'submit'<button> все еще находится type в момент возврата обработчика событий.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.info("form onSubmit");
    event.preventDefault();
    setShowForm(false);
  };

  return (
    <div>
      <div>
        {showForm ? (
          <button type = "submit" form = "videoForm">
            Upload Video
          </button>
        ) : (
          <button type = "button" onClick = {() => setTimeout(() => setShowForm(true))}>
            Show Form
          </button>
        )}
        {showForm && (
          <form id = "videoForm" onSubmit = {onSubmit}>
            <input />
          </form>
        )}
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
  1. Не меняйте 'button' на type; используйте по 1 элементу <button> для каждого типа. В React для достижения этой цели вы можете использовать реквизит <button> на одном из компонентов/элементов.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.info("form onSubmit");
    event.preventDefault();
    setShowForm(false);
  };

  return (
    <div>
      <div>
        {showForm ? (
          <button type = "submit" form = "videoForm">
            Upload Video
          </button>
        ) : (
          <button type = "button" onClick = {() => setShowForm(true)} key = "s-btn">
            Show Form
          </button>
        )}
        {showForm && (
          <form id = "videoForm" onSubmit = {onSubmit}>
            <input />
          </form>
        )}
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

Другие вопросы по теме

Похожие вопросы

SwiperJs: я показываю группы из двух слайдов, они должны быть центрированы, но я даже не могу этого добиться, ограничивая ширину слайдов
Uncaught TypeError: невозможно прочитать свойства неопределенного типа (чтение «setPopup»)
Ошибка: не удалось найти значение контекста реакции-редукса; убедитесь, что компонент завернут в <Provider> в собственном приложении React Expo
Электронный магазин возвращает «Свойство 'set'/'get' не существует по типу»
Пользовательские фрагменты в AstroJS
Я создал игру «Крестики-нолики». Есть проблема, с которой я столкнулся: всякий раз, когда игра была вничью, она печатает значение счета 2, хотя должно печатать 1
Узлы клонирования DOM Manipulation и размещение значений
Как выполнить скрипт после загрузки компонента в Лит-Элемент
Поповер Bootstrap 5 в адаптивном JS DataTable не работает должным образом
Шуточный макет «TypeError: невозможно назначить свойство только для чтения»