React component is triggering unwanted navigation/uri query

Viewed 8

I have been working with React for YEARS and have yet to encounter this phenomenon. If you can crack it, you'll be my hero forever

The Setup

I have a shared component. It is a wrapper for some buttons that appear at the bottom of several different pages (most use cases are steps in a form. The last of those buttons ALWAYS throws a modal to cancel setup.

I am using the shared component in ALL the following use cases:

  1. ✔ The first page of a multi-step form. Works fine, throws modal.
  2. ✔ The second page of a multi-step form. Works fine, throws modal.
  3. ❌ The third page of a multi-step form. Fails. See description below
  4. ❌ The fourth page of a multi-step form. Fails
  5. ✔ The review page after the form is completed. Works fine again.

The component itself contains just a button that triggers a useState() setter locally, which toggles the modal open/closed.

The Problem

On the pages where it doesn't work, the component throws all the form values on the page up into the URL as a query string. see image - green underlined portion is added on modal trigger

This triggers a page reload and of course things break.

Expected Result

I should be able to click "cancel" button and the modal pops. Nothing more, nothing less.

The (relevant) code

const IntakeLossButtons = ({
    // PRIMARY BUTTON PROPS
    buttonText,
    onButtonClick,
    buttonDisabled,
    buttonSpinning,
    buttonAriaLabel,
    // CANCEL LINK AT BOTTOM
    idToCancel,
    saveAction,
    onCancel
}) => {
    const [showCancelModal, setShowCancelModal] = useState(false)

    return (
        <div className={styles.buttonsWrapper}>
            <SpinnerButton
                type="primary"
                text={buttonText}
                disabled={buttonDisabled}
                spinning={buttonSpinning}
                onClick={onButtonClick}
                ariaLabel={buttonAriaLabel}
            />

            <button 
                className="btnLink"
                id="cancel-id" 
                tabIndex="0" 
                aria-label={translations.cancelBtnAria ||"Opens a modal to cancel your claim"} 
                color="secondary" 
                onClick={()=>setShowCancelModal(true)}
            >
                Cancel Setup
            </button>
            
            <CancelModal
                isOpen={showCancelModal}
                idToCancel={idToCancel}
                onCancel={onCancel}
                onSaveForLaterAction={saveAction} 
                onCloseModal={()=>setShowCancelModal(false)}
            />
        </div>
    )
}

export default IntakeLossButtons;

WTF?

What would cause this type of behavior? I have tried googling and reading what might cause this. I have logged everything I can log and I still don't know what is causing such a weird behavior.

Any ideas?

1 Answers

It sounds like maybe you forgot to do:

 e.preventDefault();

inside the onSubmit handler of your form. In fact, it looks like you don't even have a <form> at all, just a <button> (one with no type attribute, which means it will default to being a submit button).

You need to wrap the button in a <form> with such a submit handler. If you don't do that, when you "submit the form" (ie. click the button) it will use all the form's inputs to generate a new URL, and then it will send you to do that URL.

This is the "default" behavior for forms in browsers. If you go to www.google.com, for instance, and search for "cute puppies", you'll see the URL changes to have ?q=cute+puppies, because Google relies on not preventing this default behavior.

Related