由于 setState 更改了滑块在状态中的值,并且发生在实际滑块移动之后,因此滑块滞后了很多。我见过人们使用去抖动来解决这个问题,但它的效果并不好,我觉得必须有一个更务实的解决方案。去抖动只是使问题不那么明显,它不能从根本上解决它。
有什么想法吗?
<!-- language: lang-js -->
<Slider
value={this.state.someValue}
maximumValue={this.state.sliderMaximumValue}
minimumValue={0}
onValueChange={(someValue) => this.setState({someValue})}
/>
您只需不将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
prop)。
我有一个组件,我必须显示不断变化的滑块值,而不会使滑块滞后。所以我这样做了:
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
并在某个文本组件中显示它。
我希望我把自己说清楚了。如果没有,请询问,我会详细说明。:)
使用您发布的代码,如果您正在渲染一堆其他内容以及组件中的滑块,则很难说发生了什么,那么在每个值更改时调用 setState 是一件坏事,它会触发许多渲染的方式,这就是为什么它滞后的原因,因为它必须重新渲染很多。
解决 方案:
1)如果你不需要在UI上反映任何内容,你可以在ValueChange={(someValue) => this.state.sliderValue = someValue}上执行,这不会触发渲染,但会在状态上保留滑块值。
2)将滑块提取到它自己的纯组件中,并将滑块状态保留为该组件,当您更改滑块集状态时,将仅重新渲染滑块组件部分而不是整个屏幕。
希望这对你有帮助。
我建议使用onSlidingComplete
而不是onValueChange
,因为它只会在用户操作结束时设置状态(并刷新视图)。
编辑这不会影响您对滑块的数字显示值的更新,如 DOCS 所述:
这不是受控组件,您无需更新值 在拖动过程中。
我们可以像下面这样使用onTouchStart和onTouchEnd:
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;
你应该改用setNativeProps
。正如这个答案所说。
更多关于原生道具的信息。
你应该得到这样的东西:
<>
<TextInput
value={value.toLocaleString('pt-BR', {maximumFractionDigits: 2, minimumFractionDigits: 2})}
onChangeText={(value) => {
setValue(value);
}}
ref={inputRef}
/>
<Slider
value={value}
onValueChange={value => {
inputRef.current?.setNativeProps({text: value});
}}
/>
</>;
我使用了useRef而不是useState,它工作正常,没有任何滞后