简体   繁体   中英

Changing the value of a react input component with JS doesn't fire the inputs onChange event

I have a range input that has a few things happening onChange . This works as I'd expect with manual click/drag usage. However, when I try to change the value with JavaScript, my onChange event doesn't seem to fire.

Here is my code:

const App = () => {
  const [currentValue, setCurrentValue] = useState(0);

  const setRangeValue = () => {
    const range = document.querySelector("input");

    range.value = 50;
    range.dispatchEvent(new Event("change", { bubbles: true }));
  };

  return (
    <div className="App">
      <h1>Current Value: {currentValue}</h1>

      <input
        type="range"
        min={0}
        max={100}
        step={10}
        onChange={e => {
          console.log("Change!");
          setCurrentValue(+e.target.value);
        }}
        defaultValue={0}
      />

      <button onClick={setRangeValue}>Set current value to 50</button>
    </div>
  );
};

And here it is (not) working in CodeSandbox: https://codesandbox.io/s/divine-resonance-rps1n

NOTE:

Just to clarify. My actual issue comes from testing my component with jest/react testing library. The button demo is just a nice way to visualize the problem without getting into the weeds of having to duplicate all of my test stuff too.

    const getMessage = (value, message) => {
        const slider = getByRole('slider');
        fireEvent.change(slider, { target: { value } });
        slider.dispatchEvent(new Event('change', { bubbles: true }));
        return getByText(message).innerHTML;
    };

When the fireEvent changes the value, it doesn't run the onChange events attached to the input. Which means that getByText(message).innerHTML is incorrect, as that will only update when a set hook gets called onChange . (All of this works when manually clicking/dragging the input slider, I just can't "test" it)

Any help would be great!

The issue is that React has a virtual DOM which doesn't connect directly to the DOM. Note how the events from React are SyntheticEvents. They are not the actual event from the DOM. https://github.com/facebook/react/issues/1152

If this is for a unit test, create a separate component for the slider and text and make sure they perform as expected separate from each other with props.

For a more in-depth article on how to specifically test a range slider, checkout https://blog.bitsrc.io/build-and-test-sliders-with-react-hooks-38aaa9422772

Best of luck to ya!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM