react-component / slider

React Slider
https://slider.react-component.now.sh/
MIT License
3.02k stars 764 forks source link

Specifying value AND onAfterChange handler locks slider #111

Closed ChrisRus closed 8 years ago

ChrisRus commented 8 years ago

If I specify the initial value of the slider using value AND also register a handler via onAfterChange, the handler is seemingly always called back with the initial value set via value. Additionally, the slider handle is stuck at this position and cannot be moved.

If I leave everything else constant and simply connect my handler to onChange instead everything works as expected (except I'm not getting the extra filtering).

benjycui commented 8 years ago

It works fine in demo http://react-component.github.io/slider/examples/slider.html

Maybe you should read this? https://facebook.github.io/react/docs/forms.html#controlled-components

ChrisRus commented 8 years ago

Thanks for the feedback. I actually see only use of onAfterChange w/defaultValue but not value in the examples. Could be I missed it?

I've read the React Controlled Components docs before but don't think that's exactly what's going on in my scenario (at least not obviously). Here's some JSX that works as I expect:

<Slider 
    disabled={disabled}
    min={sliderMin}
    max={sliderMax}
    marks={sliderMarks}
    step={null}
    value={viewscaleDescriptor.ordinal}
    onChange={this.onChange}
/>

But if I alter the above replacing onChange with onAfterChange the slider handle gets stuck because my this.onChange handler does not receive updated value(s) as it does when it is registered on onChange.

Not shown is my this.onChange but all that it's doing effectively is reflecting whatever value is passed to it back into viewscaleDescriptor.ordinal and re-rendering via React. Consequently, when I use onAfterChange the slider handle snaps back to the original position on re-render because I've never seen the new user-specified value.

benjycui commented 8 years ago

You could combine onChange and onAfterChange. I had update demo http://react-component.github.io/slider/examples/slider.html

For onAfterChange is just triggered when mouse up, so it cannot change Slider's value while dragging.

rscott78 commented 7 years ago

@benjycui I'm also having the same problem. Can you explain what you mean by 'combining' the two events? I assume you mean that you watch the onChange event then use it to change the state value, which in turn sets the value of the slider?

In my case, that won't work - is there another reason why the slider is locked when using onAfterChange combined with the value prop? For what it's worth, if I use defaultValue with onAfterChange, it works ok (though the slider obviously doesn't stay updated with state changes).

benjycui commented 7 years ago

Slider is a controlled component.

Jon889 commented 6 years ago

I figured it might be helpful to explain why it is a controlled component means this happens.. :) As it's a controlled component it will always display the value in the value prop. (the source of truth is the react state not the internal state of the component). This means if you have the value prop you need to update the variable in the value prop with the value from the onChange handler, else the slider will lock.

harshitsinghai77 commented 4 years ago

How to do this in typescript?

const onAfterChangeHandler = (value: any) => { console.log(typeof value) }

<Slider defaultValue={1000} onAfterChange={e => onAfterChangeHandler(e)} min = {1000} max={1000000} />

can someone help me with typescript? I have to implicitly get the value as type any. Is there any better way to do it?

siamak-khatami commented 2 months ago

I am not sure if this is the case for anyone else, but I am writing my own solution. The problem: The input slider gets locked when used with the value property without an onChange event. So, you have to use the onChange event anyway. Using onChange, the event will be triggered if you pass by every value on the slider, making lots of extra computations, which is bad for both the server-side and front-end if it is about updating the database or any charts.

A Solution:

  1. I update state variables relevant to the value on onChange event handler.
  2. I set onMouseUp (or any other event handler like onBlur), which sets a state variable (setFlag(pre=>true)).
  3. Using a useEffect hook, I am looking to see if flag==true and execute my calculations using the state values set by the onChange event handler and then again setFlag(pre=>false).

In short, onChange will only update the state value holders relevant to the slider. But when onMouseUp, the main calculations will happen using the updated values by onChange.

const [flag, setFlag] = useState(false)
const [sliderValue, setSliderValue] = useState(1)
const sliderValueRef = 1
useEffect(()=>{ 
        if(flag){
            // DO YOUR CALCULATIONS USING the sliderValue
            setFlag(pre=>false)
        } 
    },[flag])

 <input   type="range"  min={1} max={3}  ref={sliderValueRef }  value={sliderValue}  onChange={e=>setSliderValue(pre=>e.target.value)} onMouseUp={e=>setFlag(pre=>true)}  /> 

I hope this solves the problem.