Reputation: 2428
I have two sliders, each with an event listener. Using your mouse to adjust one slider should update a shared state, which should then cause a change in the second slider. However, I only want the event listener for the first slider to fire. In the code I have below, the second slider's event listener is also firing, as can be seen by console prints of the form "Slider y was dragged..." when dragging the first slider. Is there some way to filter out the second slider's event listener firing?
function MySlider(props) {
const sliderRef = useRef();
useEffect(() => {
const slider = sliderRef.current;
const onChange = (evt) => {
const v = evt.detail.value;
console.log("Slider " + props.name + " was dragged to: " + v);
props.update(v);
}
slider?.addEventListener('change', onChange);
return () => {
slider?.removeEventListener('change', onChange);
}
}, []);
return (
<toolcool-range-slider
id={props.name}
min={props.min}
max={props.max}
value={props.value}
step="1"
ref={sliderRef}
/>
);
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
x: 10,
y: 5,
};
}
updateX(x) {
this.setState({
x: x,
y: Math.ceil(x/2),
});
}
updateY(y) {
this.setState({y: y});
}
render() {
const x = this.state.x;
const y = this.state.y;
const minY = Math.ceil(x/2);
const maxY = x;
return (
<div>
<table><tbody>
<tr>
<td>Choose x:</td>
<td style={{padding:10}}>
<MySlider name="x" min={10} max={50}
value={this.state.x}
update={(x) => this.updateX(x) }
/>
</td>
<td>{x}</td>
</tr>
<tr>
<td>Choose a y in the range [x/2, x]:</td>
<td style={{padding:10}}>
<MySlider name="y" min={minY} max={maxY}
value={this.state.y}
update={(y) => this.updateY(y) }
/>
</td>
<td>{y}</td>
</tr>
</tbody></table>
</div>
);
}
}
export default App;
The above example uses the toolcool-range-slider library, but I am fine using any slider implementation.
Upvotes: 1
Views: 1132
Reputation: 981
The function updateX
in react component named App is updating the state of y as well, which is triggering the change event of slider-y.
I believe you are already aware of this issue as per your comment in response to Wazeed, and want a way to identify the event only when the user is interacting with the slider.
First reference: @Wazeed
Checking if the current focus element is the referenced element
Bad points: If the child element is being referenced, the comparison will return false (document.activeElement == slider)
Checking if the referenced element or any of its children have active focus in the DOM (slider.hasFocus())
const { useState, useRef, useEffect, Component } = React;
function MySlider(props) {
const sliderRef = useRef();
useEffect(() => {
const slider = sliderRef.current;
const onChange = (evt) => {
if(document.activeElement !== slider) return;
const v = evt.detail.value;
console.log("Slider " + props.name + " was dragged to: " + v);
props.update(v);
}
slider.addEventListener('change', onChange);
return () => {
slider.removeEventListener('change', onChange);
}
}, []);
return (
<toolcool-range-slider
id={props.name}
min={props.min}
max={props.max}
value={props.value}
step="1"
ref={sliderRef}
/>
);
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
x: 10,
y: 5,
};
}
updateX(x) {
this.setState({
x: x,
y: Math.ceil(x/2),
});
}
updateY(y) {
this.setState({y: y});
}
render() {
const x = this.state.x;
const y = this.state.y;
const minY = Math.ceil(x/2);
const maxY = x;
return (
<div>
<table><tbody>
<tr>
<td>Choose x:</td>
<td style={{padding:10}}>
<MySlider name="x" min={10} max={50}
value={this.state.x}
update={(x) => this.updateX(x) }
/>
</td>
<td>{x}</td>
</tr>
<tr>
<td>Choose a y in the range [x/2, x]:</td>
<td style={{padding:10}}>
<MySlider name="y" min={minY} max={maxY}
value={this.state.y}
update={(y) => this.updateY(y) }
/>
</td>
<td>{y}</td>
</tr>
</tbody></table>
</div>
);
}
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App/>
);
<script src="https://incapdns.github.io/toolcool-range-slider.min.js/index.js"></script>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
Upvotes: 2