'How can you prevent propagation of events from a MUI (v4) Slider Component

I have a MUI v4 Slider (specifically used as a range slider: https://v4.mui.com/components/slider/#range-slider) component inside an expandable component in a form, however, the onChange handler for the Slider component immediately propagates up into the parent and triggers the onClick handler which controls the hide/show.

In the child:

import { Slider } from '@material-ui/core';

export const MySliderComponent = ({ setSliderValue }) => {
  let onChange = (e, value) => {
    e.stopPropagation();
    setSliderValue(value);
  }
  return <Slider onChange={onChange} />
}

In the parent:

let [expanded, setExpanded] = useState(false);
let toggle = (e) => setExpanded(!expanded);

return (
  <React.Fragment>
    <div className={'control'} onClick={toggle}>Label Text</div>
    <div hidden={!expanded}>
      <MySliderComponent />
    </div>
  </React.Fragment>
);

Points:

  • when I click inside the slider component, but not on the slider control, it does not trigger the toggle in the parent
  • when I click on the slider control, the event immediately (on mouse down) triggers the toggle on the parent
  • throwing a e.preventDefault() in the onChange handler has no effect
  • using Material UI v4 (no I can't migrate to 5)

I don't understand why the onChange would trigger the parent's onClick. How do I prevent this, or otherwise include a Slider in expandable content at all?

Edit:

After further debugging I found that if I removed the call to setSliderValue, that the parent did not collapse/hide the expanded content. Then I checked the state of expanded and it seems to be resetting without a call to setExpanded. So it looks like the parent component is re-rendering, and wiping out the state of the useState hook each time.



Solution 1:[1]

Following solution worked for me in a simmilar problem:

  1. Give your parent component a unique id (for readability)

    div id="parent" className={'control'} onClick={toggle}

  2. Modify the parent's onClick handler (toggle):

     let toggle = (e) => {
       if (wasParentCLicked()) setExpanded(!expanded);
    
       function wasParentCLicked() {
         try {
            if (e.target.id === "parent") return true;
          } catch(error) {
    
          }
          return false;
       }
     }
    

For further help refer to the official documentation of the Event.target API: https://developer.mozilla.org/en-US/docs/Web/API/Event/target

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1