Sharcoux / slider

React-Native and React-Native-Web compatible slider
ISC License
156 stars 31 forks source link

The range value is incorrect after sliding. #94

Closed linhvovan29546 closed 5 months ago

linhvovan29546 commented 5 months ago

Describe the bug The range are not correct after sliding.

To Reproduce

Expected behavior The new minimum/maximum value must be the same as the old minimum/maximum value

Screenshots Screen Recording 2024-04-24 at 3 03 13 PM (1)

Please complete the following information:

Additional context The issue arose while sliding at high speed.

Sharcoux commented 5 months ago

I'm not sure about what you call min and max value. The min and max are defined as props. In your example, they are 0 and 100 and don't seem to evolve over time.

About your thumbs, they don't seem to behave unexpectedly. What is it that you would expect exactly?

linhvovan29546 commented 5 months ago

I'm not sure about what you call min and max value. The min and max are defined as props. In your example, they are 0 and 100 and don't seem to evolve over time.

About your thumbs, they don't seem to behave unexpectedly. What is it that you would expect exactly?

Sorry for the misunderstanding. I mean the 'range' value (e.g., range=[min value, max value]). In that example, when I slide the max thumb to 50, then I slide the min thumb with high speed, and the max thumb value changes to to 51, then to 53, and finally to 54. (My expectation was that it remains the same as the old value, which is 50.). Is that accurate?"

Sharcoux commented 5 months ago

Ok, this is unrelated to your problem, but your example shows some critical performance flaws:

  1. Your CustomThumb will generate a whole new component at every render. This will completely remount the thumbs instead of just updating them
  2. Your onSlidingComplete is generating a new function at every render. You probably want to use useCallback, or simply, use setRange directly there
  3. Your thumb change size according to its value, which can lead to a bad experience for the user

You could use something like this instead:

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import {  RangeSlider } from '@sharcoux/slider'

const Thumb = ({ value }) => {
  return(<Text style={styles.thumb}>{value}</Text>)
}

export default function App() {
  const [range,setRange]=React.useState([0, 1])
  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>
        Change code in the editor and watch it change on your phone! Save to get a shareable url.
      </Text>
      <Text style={styles.title}>
        Range Slider
      </Text>
      <RangeSlider
        range={range}                    // set the current slider's value
        minimumValue={0}                  // Minimum value
        maximumValue={100}                  // Maximum value
        step={1}                          // The step for the slider (0 means that the slider will handle any decimal value within the range [min, max])
        minimumRange={undefined}                  // Minimum range between the two thumbs (defaults to --step--)
        crossingAllowed={true}           // If true, the user can make one thumb cross over the second thumb
        outboundColor='grey'              // The track color outside the current range value
        inboundColor='grey'               // The track color inside the current range value
        thumbTintColor='darkcyan'         // The color of the slider's thumb
        thumbStyle={undefined}            // Override the thumb's style
        trackStyle={undefined}            // Override the tracks' style
        minTrackStyle={undefined}         // Override the tracks' style for the minimum range
        midTrackStyle={undefined}         // Override the tracks' style for the middle range
        maxTrackStyle={undefined}         // Override the tracks' style for the maximum range
        vertical={false}                  // If true, the slider will be drawn vertically
        inverted={false}                  // If true, min value will be on the right, and max on the left
        enabled={true}                    // If false, the slider won't respond to touches anymore
        trackHeight={4}                   // The track's height in pixel
        thumbSize={15}                    // The thumb's size in pixel
        thumbImage={undefined}            // An image that would represent the thumb
        slideOnTap={true}                 // If true, touching the slider will update it's value. No need to slide the thumb.
        onValueChange={setRange}         // Called each time the value changed. The type is (range: [number, number]) => void
        onSlidingStart={undefined}        // Called when the slider is pressed. The type is (range: [number, number]) => void
        onSlidingComplete={undefined}     // Called when the press is released. The type is (range: [number, number]) => void
        CustomThumb={Thumb}           // Provide your own component to render the thumb. The type is a component: ({ value: number, thumb: 'min' | 'max' }) => JSX.Element
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    paddingTop: 10,
    backgroundColor: '#ecf0f1',
    padding: 20,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  thumb: {
    width: 16,
    textAlign: 'center',
  },
  title: {
    fontSize: 14,
    fontWeight: 'bold',
  },
});

About your problem itself, I published a fix. You can test v7.1.2

Thanks for your report.

linhvovan29546 commented 5 months ago

this is unrelated to your problem, but your example shows some critical performance flaws:

@Sharcoux Thanks for your suggestion. I've tested v7.1.2 and it seems that the issue still exists.(The new version looks better than the old one)

https://github.com/Sharcoux/slider/assets/84692183/ba0f7a6a-cdce-4372-b593-654b55d3e384

Example:

const Thumb = ({
  value,
}: {
  value: number;
}) => {
  return (
    <Pressable style={{ height: 20,
    width: 20,
    borderRadius: 10,
    backgroundColor: "white",
    borderWidth: 2,}}>
      <Text style={{ textAlign: "center" }}>{value}</Text>
    </Pressable>
  );
};
....
 <RangeSlider
      minimumValue={0}
      maximumValue={999}
      crossingAllowed
      step={1}
      CustomThumb={Thumb}
    />
Sharcoux commented 5 months ago

No, the problem is solved. You just forgot to set the minimum range to 0. It defaults to step, which is 1 in your example.

linhvovan29546 commented 5 months ago

Thanks @Sharcoux, understood. When do you plan to release this version?

Sharcoux commented 5 months ago

It is already released...