React Native滑块onValueChange调用setState使滑块滞后

时间:2019-02-19 09:42:42

标签: javascript reactjs react-native

由于setState在状态下更改了滑块的值并且在实际滑块移动之后发生,所以滑块滞后了很多时间。我已经看到人们使用防弹跳功能来解决此问题,但效果不佳,我觉得必须有一个更加实用的解决方案。消除抖动只会使问题不那么明显,也不能从根本上解决问题。

有什么想法吗?

<!-- language: lang-js -->
<Slider
    value={this.state.someValue}
    maximumValue={this.state.sliderMaximumValue}
    minimumValue={0}
    onValueChange={(someValue) => this.setState({someValue})}
/>

4 个答案:

答案 0 :(得分:1)

我建议使用onSlidingComplete而不是onValueChange,因为它仅在用户操作结束时才设置状态(并刷新视图)。

编辑 如DOCS所述,这不会影响您对滑块的数字显示值的更新:

  

这不是受控组件,您不需要更新值   在拖动过程中。

答案 1 :(得分:1)

只需通过 not 即可将value道具传递到<Slider />,即可实现所需的目标。因此,像这样:

<!-- language: lang-js -->
<Slider
  // value={this.state.someValue} // commented out :D
  maximumValue={this.state.sliderMaximumValue}
  minimumValue={0}
  onValueChange={(someValue) => this.setState({someValue})}
/>

就是这样! :D

但是! 如果需要不断显示滑块的变化值(根据需要),可以执行以下操作:

在组件中为一个实际状态创建2个状态。一个显示,另一个是要传递给<Slider />的实际值(在这种情况下,您无需注释掉value道具)。

我有一个组件,其中必须显示不断变化的滑块值,而滑块不会滞后。所以我这样做了:

const [displayTotalQuantity, setDisplayTotalQuantity] = useState(FUEL_AMOUNT_MINIMUM);  
const [totalQuantity, setTotalQuantity] = useState(FUEL_AMOUNT_MINIMUM);

<Text> {displayTotalQuantity} </Text>
<Slider
   style={slider.baseStyles}
   step={STEP}
   value={totalQuantity}
   minimumValue={MINIMUM}
   maximumValue={MAXIMUM}
   minimumTrackTintColor={mainColors.irisBlue}
   maximumTrackTintColor={mainColors.sliderMaxTintGray}
   thumbTintColor={mainColors.irisBlue}
   onSlidingComplete={value => setTotalQuantity(value)}
   onValueChange={value => setDisplayTotalQuantity(value)}
 />

因此,您需要通过value道具传递实际状态,但仅更新onSlidingComplete。另一方面,在每次更改时更新display状态,即onValueChange,并将其显示在某些文本组件中。

我希望我能说清楚。如果没有,请询​​问,我会详细说明。 :)

答案 2 :(得分:0)

使用已发布的代码,很难说出要渲染的其他东西以及组件中的滑块,然后在每次值更改时调用setState都是一件坏事,它触发了许多渲染的方式,这就是为什么它滞后了因为它需要重渲染。

解决方案:

1)如果不需要在UI上反映任何内容,则可以执行onValueChange = {(someValue)=> this.state.sliderValue = someValue},这不会触发渲染,但会保留状态上的滑块值。

2)将滑块提取到其自己的纯组件中,并以这种方式将滑块状态保持为该组件,当您更改滑块设置状态时,将仅重新渲染滑块组件的一部分,而不是整个屏幕。

希望这对您有所帮助。

答案 3 :(得分:0)

我们可以像下面这样使用 onTouchStartonTouchEnd

import React, { useState } from 'react';
import { View } from 'react-native';

import Slider from '@react-native-community/slider';

const MySlider = () => {
  const [value, setValue] = useState(0);
  const [isTouchEnded, setIsTouchEnded] = useState(false);

  return (
    <View>
      <Slider
        minimumValue={0}
        maximumValue={10}
        value={isTouchEnded ? value : 0}
        onValueChange={(e) => setValue(e)}
        onTouchEnd={() => setIsTouchEnded(true)}
        onTouchStart={() => setIsTouchEnded(false)}
      />
    </View>
  );
};

export default MySlider;