Skip to content

Commit 9f14e92

Browse files
authored
Merge pull request #574 from nmassey/fix-useSharedValue-async-updates
fix: `onGestureEnd` -> `endWithSpring` uses outdated data via `useSharedValue`
2 parents d859eb2 + 86da6ac commit 9f14e92

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

src/components/ScrollViewGesture.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,18 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
116116
);
117117

118118
const endWithSpring = React.useCallback(
119-
(onFinished?: () => void) => {
119+
(scrollEndTranslationValue: number,
120+
scrollEndVelocityValue: number,
121+
onFinished?: () => void,
122+
) => {
120123
"worklet";
121124
const origin = translation.value;
122-
const velocity = scrollEndVelocity.value;
125+
const velocity = scrollEndVelocityValue;
123126
// Default to scroll in the direction of the slide (with deceleration)
124127
let finalTranslation: number = withDecay({ velocity, deceleration: 0.999 });
125128

126129
// If the distance of the swipe exceeds the max scroll distance, keep the view at the current position
127-
if (maxScrollDistancePerSwipeIsSet && Math.abs(scrollEndTranslation.value) > maxScrollDistancePerSwipe) {
130+
if (maxScrollDistancePerSwipeIsSet && Math.abs(scrollEndTranslationValue) > maxScrollDistancePerSwipe) {
128131
finalTranslation = origin;
129132
}
130133
else {
@@ -137,9 +140,9 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
137140
* */
138141
if (pagingEnabled) {
139142
// distance with direction
140-
const offset = -(scrollEndTranslation.value >= 0 ? 1 : -1); // 1 or -1
143+
const offset = -(scrollEndTranslationValue >= 0 ? 1 : -1); // 1 or -1
141144
const computed = offset < 0 ? Math.ceil : Math.floor;
142-
const page = computed(-translation.value / size);
145+
const page = computed(-origin / size);
143146

144147
if (loop) {
145148
const finalPage = page + offset;
@@ -178,9 +181,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
178181
snapEnabled,
179182
translation,
180183
pagingEnabled,
181-
scrollEndVelocity.value,
182184
maxScrollDistancePerSwipe,
183-
scrollEndTranslation.value,
184185
maxScrollDistancePerSwipeIsSet,
185186
],
186187
);
@@ -335,9 +336,10 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
335336
"worklet";
336337

337338
const { velocityX, velocityY, translationX, translationY } = e;
338-
scrollEndVelocity.value = isHorizontal.value
339+
const scrollEndVelocityValue = isHorizontal.value
339340
? velocityX
340341
: velocityY;
342+
scrollEndVelocity.value = scrollEndVelocityValue; // may update async: see https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue#remarks
341343

342344
let panTranslation = isHorizontal.value
343345
? translationX
@@ -349,9 +351,9 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
349351
else if (fixedDirection === "positive")
350352
panTranslation = +Math.abs(panTranslation);
351353

352-
scrollEndTranslation.value = panTranslation;
354+
scrollEndTranslation.value = panTranslation; // may update async: see https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue#remarks
353355

354-
const totalTranslation = scrollEndVelocity.value + scrollEndTranslation.value;
356+
const totalTranslation = scrollEndVelocityValue + panTranslation;
355357

356358
/**
357359
* If the maximum scroll distance is set and the translation `exceeds the maximum scroll distance`,
@@ -374,7 +376,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
374376
translation.value = withSpring(withProcessTranslation(nextPage), onScrollEnd);
375377
}
376378
else {
377-
endWithSpring(onScrollEnd);
379+
endWithSpring(panTranslation, scrollEndVelocityValue, onScrollEnd);
378380
}
379381

380382
if (!loop)

0 commit comments

Comments
 (0)