skip to Main Content

I’m creating my custom React component with some extra features. I would like to keep it as close to the default browser behavior as possible. Whenever I change something in the form’s input I would like the change event to bubble up to the form. Unfortunately, I can’t make it work.

I’ve read that the "change" event is apparently some special even in React’s synthetic event system. None of the proposed solutions worked for me as they were for older React versions.

To simplify my problem I created this demo and what I would like to do is to trigger the form.onChange from within input’s onPointerDown or whatever other event handler. Of course I can’t call the form.onChange directly as I’m not in the control of this part of the code. Everything should be done through events bubbling. Is it even possible in React? I’ve tested it in some of the popular UI libraries and so far none of them does that for non-native select components.

export function Demo() {
  return (
    <form
      onChange={(event) => {
        const form = event.currentTarget;
        const formData = new FormData(form);
        console.log(JSON.stringify(Array.from(formData)));
      }}
    >
      <input
        name="name"
        onPointerDown={(event) => {
          const changeEvent = new Event("change", { bubbles: true });
          event.currentTarget.dispatchEvent(changeEvent);
        }}
      />
    </form>
  );
}

2

Answers


  1. You can’t directly call onChange event of the form by dispatching it from an input.

    The onChange event of the form will trigger on any form’s inputs changes.

    React optimizes event handling by tracking the value changes of form elements. Without actually changing the input’s value, React might not recognize the event as a meaningful change, even if the event is dispatched.

    I think this is reasonable, because what’s the point of calling onChange on a form (from input’s onPointerDown in your case) if the values of its inputs haven’t changed?

    Login or Signup to reply.
  2. Solution 1 : Add events to form on need basis.

    The following code shows the same.

    The coding highlights:

    a. A ref object is used to get access to the form object.

    b. The handler addEventToForm will add events to the form object.

    c. The handler listenerForAllFormEvents is the same handler will listen to all events added.

    App.js

    import { useRef } from 'react';
    
    export default function Demo() {
      const refForm = useRef();
    
      function listenerForAllFormEvents(event) {
        const form = event.currentTarget;
        const formData = new FormData(form);
        console.log(JSON.stringify(Array.from(formData)));
      }
    
      function addEventToForm(event) {
        const eventName = event._reactName.substr(2).toLowerCase();
        refForm.current.addEventListener(eventName, listenerForAllFormEvents);
      }
    
      return (
        <form ref={refForm}>
          <input
            name="name"
            onPointerDown={addEventToForm}
            onChange={addEventToForm}
          />
        </form>
      );
    }
    

    Test run

    // Events vs.                            Console log generated:
    // ------------------------------------------------------------
    // On pointing mouse on the input field  [["name",""]]
    // On pressing tab from the field
    // after typing the text 'good name'     [["name","good name"]]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search