zillow / react-slider

Accessible, CSS agnostic, slider component for React.
https://zillow.github.io/react-slider
MIT License
883 stars 231 forks source link

Thumb is not moving when the value is changed by another action #248

Closed raulneto closed 2 years ago

raulneto commented 2 years ago

Description

The value is being changed dynamically by another action (a reset function). When the value prop changes I set new value into state but the thumb is not moving. It is only moving when dragged manually.

componentWillReceiveProps(nextProps) {
    this.setState({ value: Number(nextProps.value) })
  }

  handleChange(value) {
    const { onChange, options } = this.props
    onChange(this.getSelectedOption(value, options))
    this.setState({ value })
  }

  render() {
    const { options, rangeOptions } = this.props
    const { value } = this.state
    const { min, max, increment } = rangeOptions

    return (
      <div className="full-width">
        <ReactSlider
          className="RangeSlider"
          thumbClassName="RangeSlider--thumb"
          trackClassName="RangeSlider--track"
          markClassName="RangeSlider--mark"
          value={value}
          min={Number(min)}
          max={Number(max)}
          step={Number(increment)}
          onChange={this.handleChange}
        />
      </div>
    )
kris-ellery commented 2 years ago

@raulneto could you please replicate it in CodeSandbox? react-slider requires React 16 or 17 as peer dependency.

netgfx commented 2 years ago

Hm having the same issue, changing the value via state change does move the thumb but it doesn't call the onChange function

stonebk commented 2 years ago

Hm having the same issue, changing the value via state change does move the thumb but it doesn't call the onChange function

This is expected behavior because the slider is behaving as a controlled component. onChange will only fire on user events, not changes to value that are passed in, otherwise you could have a feedback loop.

raulneto commented 2 years ago

@raulneto could you please replicate it in CodeSandbox? react-slider requires React 16 or 17 as peer dependency.

Yep :( the problem was that react-slider uses getDerivedStateFromProps from React 16+ an it is not changing component state as the props changes. So I'm passing a new key to the component when slider moves. It is not a good practice but it is just a workaround. Next steps will be upgrading whole application for React 16.

stug111 commented 10 months ago

As workaround, create new class component, extends from ReactSlider and update method componentDidUpdate

import ReactSlider, { ReactSliderProps } from 'react-slider'

export class ExtendsReactSlider<
  T extends number | ReadonlyArray<number> = number,
> extends ReactSlider<T> {
  constructor(props: ReactSliderProps<T>) {
    super(props)
  }

  componentDidUpdate(prevProps: ReactSliderProps<T>, prevState: Readonly<{}>) {
    super.componentDidUpdate?.(prevProps, prevState)

    if (prevProps.value !== this.props.value) {
      this.setState({ value: this.props.value })
    }
  }
}