我正在try 根据是否显示表单在ReactJS中的两个HTML按钮之间有条件地切换.基本上,如果显示表单,则显示提交按钮,如果未显示,则显示常规按钮来显示表单.

这是我拥有的代码.(我正在使用Antd的按钮组件,但我也try 使用普通的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>

我遇到的问题是,当表单没有显示并单击"显示表单"按钮时,表单会正确显示并且按钮会切换,但表单提交事件正在触发,这不是我所期望或想要的.

有什么 idea 吗?我如何解决这个问题?我还try 了以下操作,但得到了相同的结果.

<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>

如有任何帮助,我们将不胜感激.

推荐答案

这种行为与<button>的默认type无关,因为OP已经通过htmlType prop将底层HTML <button>元素的type设置为'button'. 这种行为也可以在没有React的情况下重现,如下所示:

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

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

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

btnW.onclick = function (event) {
  console.log(`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>元素),只更改了htmlTypeprops (以及底层元素的type属性).

要解决这个问题,要么:

  1. 呼叫活动收听者内的preventDefault().这将阻止单击与正在提交该表单的表单关联的提交<button>的默认操作.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.log("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仍然是'button'.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.log("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中,您可以在其中一个组件/元素上使用keyprops 来实现这一目标.

const { useState } = React;

const App = () => {
  const [showForm, setShowForm] = useState(false);
  const onSubmit = (event) => {
    console.log("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>

Javascript相关问答推荐

在nodejs中使用快速路由的API路径

React native在不首次加载时渲染的挂钩比上一次渲染期间渲染的挂钩更多

使用JavaScript/PHP将二维码保存为服务器端的图像

错误:找不到react-redux上下文值;请确保该组件包装在React原生Expo应用程序中的提供者中

JavaScript Date对象在UTC中设置为午夜时显示不正确的日期

如何指定1条记录1个表?

为什么使用MAX_SAFE_INTEGER生成随机整数时数字分布不准确?

如何在使用fast-xml-parser构建ML时包括属性值?

如何使用侧边滚动按钮具体滚动每4个格?

从实时数据库(Firebase)上的子类别读取数据

我开始使用/url?q=使用Cheerio

MathJax可以导入本地HTML文档使用的JS文件吗?

无法读取未定义错误的属性路径名''

可更改语言的搜索栏

Reaction Native中的范围滑块

用于在路径之间移动图像的查询

我想将Sitecore搜索面过滤器从多个转换为单个

如何访问此数组中的值?

如何使用Astro优化大图像?

用Reaction-RT-Chart创建实时条形图