反应原生 PanResponder 可拖动被 setState 中断
我有一个状态变量来跟踪秒数
const [seconds, setSeconds] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
if (seconds > 59) {
setSeconds(0)
} else {
setSeconds((seconds) => seconds + 1)
}
}, 1000)
return () => clearInterval(interval)
}, [seconds])
我也在使用可拖动的平移响应器
import React, { useState, useRef, ReactNode } from 'react'
import {
StyleSheet,
Animated,
PanResponder,
PanResponderGestureState,
Text
} from 'react-native'
const Draggable = (props) => {
const { draggable, isDropZone, moveToDropArea } = props
const [showDraggable, setshowDraggable] = useState(true)
const pan = useRef<Animated.AnimatedValueXY>(new Animated.ValueXY()).current
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event([
null,
{
dx: pan.x,
dy: pan.y,
},
]),
onPanResponderRelease: (e, gesture) => {
if (isDropZone(gesture)) {
setshowDraggable(false)
moveToDropArea()
} else {
Animated.spring(pan, {
toValue: { x: 0, y: 0 },
useNativeDriver: false,
}).start()
}
pan.flattenOffset()
},
})
return (
<Animated.View {...panResponder.panHandlers} style={[pan.getLayout()]}>
<Text>{seconds}</Text>
</Animated.View>
)
}
当我尝试拖动 draggable 时,它会移动,但是当状态更新时,组件会重新渲染并且 Draggable 项回到原来的位置。
如何防止这种情况发生?
提前致谢。
答案 0 :(得分:0)
试着像这样写你的 useEffect 钩子:
useEffect(() => {
const interval = setInterval(() => {
setSeconds(currentSeconds => currentSeconds > 59 ? 0 : currentSeconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
这样就不会在每次秒的状态改变时触发。
但是,更改状态仍然会使您的组件重新渲染。如果你想防止重新渲染,你应该使用 useRef 而不是 useState。
const seconds = useRef(0);
useEffect(() => {
const interval = setInterval(() => {
seconds.current = seconds.current > 59 ? 0 : seconds.current + 1;
}, 1000);
return () => clearInterval(interval);
}, [seconds]);
console.log(seconds.current); // will log the last saved number of seconds before the last re-render
但是如果您需要显示秒的变化,您将需要您的组件在秒状态变化时重新渲染。在这种情况下,我建议您将滚动逻辑与另一个(可能是父)组件分开,这样它就不会在由秒的状态更改引起的重新渲染时重置。
答案 1 :(得分:0)
在 useEffect 钩子的第二个参数中传递空数组。
useEffect钩子在组件挂载到dom时运行回调函数,类似于类组件中的componentDidMount生命周期方法。
setInterval 函数每隔一秒运行一次 setSeconds 方法。
在 useEffect 钩子中,我们返回了一个带有计时器参数的 clearInterval 函数,这样当组件从 dom 中卸载时 setInterval 函数就会停止,这类似于 componentWillUnmount 方法。
空数组将在 mount 上运行 useEffect,在整个生命周期中保持沉默。
useEffect(() => {
const interval = setInterval(() => {
if (seconds > 59) {
setSeconds(0)
} else {
setSeconds((seconds) => seconds + 1)
}
}, 1000)
return () => clearInterval(interval)
},[])