Saturday, 15 October 2022

React: multiple sliders sharing a common state

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=>
              <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=>
              <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.



from React: multiple sliders sharing a common state

No comments:

Post a Comment