react: Bug:

State change and event trigger not behaving as expected.

React version: 18.2.0

Steps To Reproduce

  1. Create the component - code below.
import { useState } from "react";

export default function App() {
  const [clicked, setClicked] = useState(false);

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        console.log("form submitted!");
      }}
    >
      {!clicked ? (
        <button type="button" onClick={() => setClicked(true)}>
          Type "button"
        </button>
      ) : (
        <button type="submit" onClick={() => setClicked(false)}>
          Type "submit"
        </button>
      )}
    </form>
  );
}
  1. Click on the button - when it is type=“button” it should not submit, but the effect is opposite.

Link to code example:

https://codesandbox.io/s/awesome-currying-c6kts8?file=/src/App.js

The current behavior

Form gets submitted when button has type=“button” and does not get submitted when button has type=“submit”.

The expected behavior

The form should be submitted when button has type=“submit”

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 2
  • Comments: 16

Most upvoted comments

Hi, @mayank1513 can you try the code I have mentioned below , I think it will solve your problem and let me know if there is anything wrong.

`export default function App() { const [clicked, setClicked] = useState(false);

return ( <form onSubmit={(e) => { e.preventDefault(); console.log(“form submitted!”); }} > {!clicked ? ( <button type=“submit” onClick={() => setClicked(true)}> “button” </button> ) : ( <button type=“button” onClick={() => setClicked(false)}> “submit” </button> )} </form> ); }`

Greetings @mayank1513 Here is the modified code.

import { useState } from "react";

export default function App() {
const [clicked, setClicked] = useState(false);

return (
<form
onSubmit={(e) => {
e.preventDefault();
console.log("form submitted!");
}}
>
{!clicked ? (
<button
type="button"
onClick={() => {
const timer = setTimeout(() => {
setClicked(true);
clearTimeout(timer);
}, 0);
}}
>
Type "button"

) : (
<button
type="submit"
onClick={() => {
const timer = setTimeout(() => {
setClicked(false);
clearTimeout(timer);
}, 0);
}}
>
Type "submit"

)}

);
}

The issue was that React updates the virtual dom faster than the real dom. So we must add the async behaviour to the onClick event where the state is being changed.

I changed code and add a preventDefault to button

import { useState } from "react";

export default function App() {
  const [clicked, setClicked] = useState(false);

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        setClicked(true);
        console.log("form submitted!");
      }}
    >
      {!clicked ? (
        <button type="submit">Type "submit"</button>
      ) : (
        <button
          type="button"
          onClick={(e) => {
            e.preventDefault();
            setClicked(false);
          }}
        >
          Type "button"
        </button>
      )}
    </form>
  );
}

Please check the code sandbox carefully. Event is triggered only for one type of button, not both. You can even verify this by removing the condition and rendering both buttons together.

This behavior that you are seeing is because the form’s onSubmit event is triggered regardless of the button type always… Maybe you should move your state modifiers outside the buttons

Try this

import { useState } from "react";

export default function App() {
  const [clicked, setClicked] = useState(false);

  const handleFormSubmit = (e) => {
    e.preventDefault();
    if (clicked) {
      setClicked(false)
      console.log('form submitted!');
      // Perform other necessary actions
    } else {
      setClicked(true)
    }
  };

  return (
    <form>
      {!clicked ? (
        <button type="button" onClick={(e)=>handleFormSubmit(e)}>
          Type "button"
        </button>
      ) : (
        <button type="submit" onClick={(e)=>handleFormSubmit(e)}>
          Type "submit"
        </button>
      )}
    </form>
  );
}

You can also use e.target.form.submit inside the handler to in fact submit the form.

Action corresponding to the button which I click should be triggered. Not the other button.

Hi, why are you tagging type=“submit” as “button” and vice-versa? These values are used to demonstrate the current working and understand why it is working this way.