I'm calling the useAnimatedScrollHandler
hook from react-native-reanimated to handle my onScroll
function on an Animated.ScrollView
. This hook works as expected but I now want to disable a custom button (My FlatButton) based on the currentIndex
which is a sharedValue
. But when the sharedValue changes the screen doesn't get rerendered, because the state doesn't change so the look of my button remains the same.
Is there a way to force a rerender inside of a worklet, or is it possible to use useState
to force a rerender from inside a worklet?
const scrollHandler = useAnimatedScrollHandler((event) => {
translationX.value = event.contentOffset.x
if (event.contentOffset.x < width * 0.5 && currentIndex.value != 0) {
currentIndex.value = 0
} else if (
event.contentOffset.x > width * 0.5 &&
event.contentOffset.x < width * 1.5 &&
currentIndex.value != 1
) {
currentIndex.value = 1
} else if (event.contentOffset.x > width * 1.5 && currentIndex.value != 2) {
currentIndex.value = 2
}
})
<FlatButton
label="Next"
disabled={
(currentIndex.value == 0 && (!firstName || !lastName)) ||
(currentIndex.value == 1 && (!dateOfBirth || !sex)) ||
(currentIndex.value == 2 &&
(!streetNumber || !postalCode || !city || !state || !country))
}
onPress={() => {
if (currentIndex.value == 0) {
scrollRef.current
?.getNode()
.scrollTo({ x: width, animated: true })
} else if (currentIndex.value == 1) {
scrollRef.current?.getNode().scrollToEnd({ animated: true })
}
}}
/>
I just found out that reanimated offers the function runOnJS which makes it possible to run a javscript function like setState
inside a worklet. So just create a wrapper function, like in my case toggleIndex
in which you interact with your state and call this function inside runOnJS
from your worklet.
const [currentIndex, setCurrentIndex] = useState(0)
const toggleIndex = (index: number) => {
setCurrentIndex(index)
}
const scrollHandler = useAnimatedScrollHandler((event) => {
translationX.value = event.contentOffset.x
if (event.contentOffset.x < width * 0.5 && currentIndex != 0) {
runOnJS(toggleIndex)(0)
} else if (
event.contentOffset.x > width * 0.5 &&
event.contentOffset.x < width * 1.5 &&
currentIndex != 1
) {
runOnJS(toggleIndex)(1)
} else if (event.contentOffset.x > width * 1.5 && currentIndex != 2) {
runOnJS(toggleIndex)(2)
}
})