skip to Main Content

I have a range input with a react component, it’s only moving the slider. not triggering the callback function that’s there onChange

Trigering event explicitly isnt working either for react.

const volumeResetHandler = async () => {
  document.querySelector('input[type=range]').value = 0;//as mentioned by @mathias-s setSlv(0) should also be fine , my concern is the next line
 document.querySelector('input[type=range]').dispatchEvent(new Event("change"));
}
<input
 className="slider_input"
 type="range"
 value={slv}
 min="0"
 max="600"
 step="10"
 autoFocus
 onChange={volumeChangeHandler}
/>
<h3 onClick={volumeResetHandler} className="cursor-pointer">Reset</h3>

I was expecting volumeChangeHandler would get triggered on document.querySelector('input[type=range]').value = 0; but it doesn’t

All solutions mentioned here suffers from same issue

this does for jquery, without looking at react or javscript,
it doesnt answer as it is for jquery , changing jquery to js like this in react isn’t working
either.

So there must be something different going on with events in react.

Here is the updated code after trying useRef (as suggested by @LãNgọcHải)

import { useRef } from 'preact/hooks'
const inputRef = useRef<HTMLInputElement>(null)
const volumeResetHandler = async () => {
   inputRef.current.value = 0
}
<input
 className="slider_input"
 type="range"
 value={slv}
 min="0"
 max="600"
 step="10"
 autoFocus
 onChange={volumeChangeHandler}
 ref={inputRef}
/>
<h3 onClick={volumeResetHandler} className="cursor-pointer">Reset</h3>

Inspiration from this

2

Answers


  1. Chosen as BEST ANSWER

    I got it working with @LãNgọcHải 's code:

      const volumeResetHandler = async () => {
        inputRef.current.value = 0;
        (inputRef.current as any).addEventListener('change', volumeChangeHandler);
        (inputRef.current as any).dispatchEvent(new Event('change', { bubbles: true }));
      }
    
    

    Thanks a lot @LãNgọcHải . Only a small issue I have is I had a logic on event.isTrusted==true which is now false for explicitly triggering event. I would have to find some work around for that. I guess that's what bubbles is for ?


  2. In React, you need to use a controlled input to solve this. You should avoid using DOM manipulations like querySelector in combination with React for cases like this.

    To render a controlled input, pass the value prop to it. React will force the input to always have the value you passed.

    Use the onChange prop to call setValue to ensure that the input value always reflects the React state.

    function MyComponent() {
      const [value, setValue] = useState(10);
    
      return (
        <input
          type="range"
          value={value} // ...force the input's value to match the state variable...
          onChange={(e) => setValue(e.target.value)} // ... and update the state variable on any edits!
        />
      );
    }
    

    You can also call setValue from other buttons or elements, like this:

    function MyComponent() {
      const [value, setValue] = useState(10);
    
      const volumeResetHandler = () => {
        setValue(0);
      };
    
      return (
        <>
          <input
            type="range"
            value={value}
            onChange={(e) => setValue(e.target.value)}
          />
          <button onClick={volumeResetHandler}>Reset</button>
        </>
      );
    }
    

    If you have more logic in your volumeChangeHandler, that should be run for both volumeChangeHandler and volumeResetHandler, the idiomatic way to solve this in React would be to move that custom logic into its own function like this:

    function MyComponent() {
      const [value, setValue] = useState(10);
    
      const customChangeHandler = (value) => {
        // Do some custom logic here
        setValue(value);
      };
    
      const volumeResetHandler = () => {
        customChangeHandler(0);
      };
    
      const volumeChangeHandler = (e) => {
        customChangeHandler(e.target.value);
      };
    
      return (
        <>
          <input
            type="range"
            value={value}
            onChange={volumeChangeHandler}
          />
          <button onClick={volumeResetHandler}>Reset</button>
        </>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search