Skip to content

Commit 57a18ad

Browse files
committed
fix: index bug
fix #185
1 parent 9741beb commit 57a18ad

File tree

6 files changed

+62
-59
lines changed

6 files changed

+62
-59
lines changed

docs/props.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
| testID || | string | Used to locate this view in end-to-end tests |
2121
| onSnapToItem || | (index: number) => void | Callback fired when navigating to an item |
2222
| onScrollBegin || | () => void | Callback fired when scroll begin |
23-
| onScrollEnd || | (previous: number, current: number) => void | Callback fired when scroll end |
23+
| onScrollEnd || | (index: number) => void | Callback fired when scroll end |
2424
| withAnimation || | {type: 'spring';config: WithSpringConfig;} \| {type: 'timing';config: WithTimingConfig;} | Specifies the scrolling animation effect |
2525
| panGestureHandlerProps || {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
2626
| windowSize || 0 | number | The maximum number of items that can respond to pan gesture events, `0` means all items will respond to pan gesture events |

docs/props.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
| testID || | string | 在 E2E 测试中用来定位视图 |
2121
| onSnapToItem || | (index: number) => void | 切换至另一张轮播图时触发 |
2222
| onScrollBegin || | () => void | 切换动画开始时触发 |
23-
| onScrollEnd || | (previous: number, current: number) => void | 切换动画结束时触发 |
23+
| onScrollEnd || | (index: number) => void | 切换动画结束时触发 |
2424
| withAnimation || | {type: 'spring';config: WithSpringConfig;} \| {type: 'timing';config: WithTimingConfig;} | 指定滚动时的动画效果 |
2525
| panGestureHandlerProps || {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
2626
| windowSize || 0 | number | 能响应平移手势事件的最大 item 数量,0 表示所有元素都会先响应 |

src/Carousel.tsx

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import React from 'react';
2-
import Animated, {
3-
runOnJS,
4-
runOnUI,
5-
useDerivedValue,
6-
} from 'react-native-reanimated';
2+
import Animated, { runOnJS, useDerivedValue } from 'react-native-reanimated';
73

84
import { useCarouselController } from './hooks/useCarouselController';
95
import { useAutoPlay } from './hooks/useAutoPlay';
@@ -88,15 +84,8 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
8884
duration: scrollAnimationDuration,
8985
});
9086

91-
const {
92-
sharedIndex,
93-
sharedPreIndex,
94-
to,
95-
next,
96-
prev,
97-
scrollTo,
98-
getCurrentIndex,
99-
} = carouselController;
87+
const { to, next, prev, scrollTo, getSharedIndex, getCurrentIndex } =
88+
carouselController;
10089

10190
const { start: startAutoPlay, pause: pauseAutoPlay } = useAutoPlay({
10291
autoPlay,
@@ -106,17 +95,15 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
10695
});
10796

10897
const _onScrollEnd = React.useCallback(() => {
109-
'worklet';
110-
const _sharedIndex = Math.round(sharedIndex.value);
111-
const _sharedPreIndex = Math.round(sharedPreIndex.value);
98+
const _sharedIndex = Math.round(getSharedIndex());
11299

113100
if (onSnapToItem) {
114-
runOnJS(onSnapToItem)(_sharedIndex);
101+
onSnapToItem(_sharedIndex);
115102
}
116103
if (onScrollEnd) {
117-
runOnJS(onScrollEnd)(_sharedPreIndex, _sharedIndex);
104+
onScrollEnd(_sharedIndex);
118105
}
119-
}, [onSnapToItem, onScrollEnd, sharedIndex, sharedPreIndex]);
106+
}, [onSnapToItem, onScrollEnd, getSharedIndex]);
120107

121108
const scrollViewGestureOnScrollBegin = React.useCallback(() => {
122109
pauseAutoPlay();
@@ -125,10 +112,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
125112

126113
const scrollViewGestureOnScrollEnd = React.useCallback(() => {
127114
startAutoPlay();
128-
/**
129-
* TODO magic
130-
*/
131-
runOnUI(_onScrollEnd)();
115+
_onScrollEnd();
132116
}, [_onScrollEnd, startAutoPlay]);
133117

134118
const scrollViewGestureOnTouchBegin = React.useCallback(pauseAutoPlay, [

src/hooks/useCarouselController.tsx

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import React from 'react';
1+
import React, { useRef } from 'react';
22
import type Animated from 'react-native-reanimated';
33
import { Easing } from '../constants';
44
import {
55
runOnJS,
6-
useDerivedValue,
6+
useAnimatedReaction,
77
useSharedValue,
88
} from 'react-native-reanimated';
99
import type {
@@ -13,6 +13,7 @@ import type {
1313
} from '../types';
1414
import { dealWithAnimation } from '@/utils/dealWithAnimation';
1515
import { convertToSharedIndex } from '@/utils/computedWithAutoFillData';
16+
import { round } from '@/utils/log';
1617

1718
interface IOpts {
1819
loop: boolean;
@@ -28,8 +29,7 @@ interface IOpts {
2829
}
2930

3031
export interface ICarouselController {
31-
sharedIndex: Animated.SharedValue<number>;
32-
sharedPreIndex: Animated.SharedValue<number>;
32+
getSharedIndex: () => number;
3333
prev: (opts?: TCarouselActionOptions) => void;
3434
next: (opts?: TCarouselActionOptions) => void;
3535
getCurrentIndex: () => number;
@@ -60,8 +60,8 @@ export function useCarouselController(options: IOpts): ICarouselController {
6060

6161
const index = useSharedValue<number>(defaultIndex);
6262
// The Index displayed to the user
63-
const sharedIndex = useSharedValue<number>(defaultIndex);
64-
const sharedPreIndex = useSharedValue<number>(defaultIndex);
63+
const sharedIndex = useRef<number>(defaultIndex);
64+
const sharedPreIndex = useRef<number>(defaultIndex);
6565

6666
const currentFixedPage = React.useCallback(() => {
6767
if (loop) {
@@ -76,31 +76,46 @@ export function useCarouselController(options: IOpts): ICarouselController {
7676
);
7777
}, [handlerOffsetX, dataInfo, size, loop]);
7878

79-
useDerivedValue(() => {
80-
const handlerOffsetXValue = handlerOffsetX.value;
81-
sharedPreIndex.value = sharedIndex.value;
82-
const toInt = (handlerOffsetXValue / size) % dataInfo.length;
83-
const isPositive = handlerOffsetXValue <= 0;
84-
const i = isPositive
85-
? Math.abs(toInt)
86-
: Math.abs(toInt > 0 ? dataInfo.length - toInt : 0);
87-
index.value = i;
88-
sharedIndex.value = convertToSharedIndex({
79+
function setSharedIndex(newSharedIndex: number) {
80+
sharedIndex.current = newSharedIndex;
81+
}
82+
83+
useAnimatedReaction(
84+
() => {
85+
const handlerOffsetXValue = handlerOffsetX.value;
86+
const toInt = round(handlerOffsetXValue / size) % dataInfo.length;
87+
const isPositive = handlerOffsetXValue <= 0;
88+
const i = isPositive
89+
? Math.abs(toInt)
90+
: Math.abs(toInt > 0 ? dataInfo.length - toInt : 0);
91+
92+
const newSharedIndexValue = convertToSharedIndex({
93+
loop,
94+
rawDataLength: dataInfo.originalLength,
95+
autoFillData: autoFillData!,
96+
index: i,
97+
});
98+
99+
return {
100+
i,
101+
newSharedIndexValue,
102+
};
103+
},
104+
({ i, newSharedIndexValue }) => {
105+
index.value = i;
106+
runOnJS(setSharedIndex)(newSharedIndexValue);
107+
},
108+
[
109+
sharedPreIndex,
110+
sharedIndex,
111+
size,
112+
dataInfo,
113+
index,
89114
loop,
90-
rawDataLength: dataInfo.originalLength,
91-
autoFillData: autoFillData!,
92-
index: i,
93-
});
94-
}, [
95-
sharedPreIndex,
96-
sharedIndex,
97-
size,
98-
dataInfo,
99-
index,
100-
loop,
101-
autoFillData,
102-
handlerOffsetX,
103-
]);
115+
autoFillData,
116+
handlerOffsetX,
117+
]
118+
);
104119

105120
const getCurrentIndex = React.useCallback(() => {
106121
return index.value;
@@ -255,12 +270,11 @@ export function useCarouselController(options: IOpts): ICarouselController {
255270
);
256271

257272
return {
258-
sharedIndex,
259-
sharedPreIndex,
260273
to,
261274
next,
262275
prev,
263276
scrollTo,
264277
getCurrentIndex,
278+
getSharedIndex: () => sharedIndex.current,
265279
};
266280
}

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export type TCarouselProps<T = any> = {
172172
/**
173173
* On scroll end
174174
*/
175-
onScrollEnd?: (previous: number, current: number) => void;
175+
onScrollEnd?: (index: number) => void;
176176
/**
177177
* On progress change
178178
* @param offsetProgress Total of offset distance (0 390 780 ...)

src/utils/log.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,8 @@
55
export function log(...msg: any) {
66
console.log(...msg);
77
}
8+
9+
export function round(number: number) {
10+
'worklet';
11+
return Math.round(number);
12+
}

0 commit comments

Comments
 (0)