Skip to content

Commit

Permalink
fix: getCurrentIndex always return last snap index even after multipl…
Browse files Browse the repository at this point in the history
…e data changes

fix #178
  • Loading branch information
dohooo committed May 4, 2022
1 parent a66eecb commit 9b03a4d
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 105 deletions.
26 changes: 24 additions & 2 deletions example/src/normal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import * as React from 'react';
import { View } from 'react-native-ui-lib';
import Carousel from 'react-native-reanimated-carousel';
import Carousel, { ICarouselInstance } from 'react-native-reanimated-carousel';
import { SBItem } from '../components/SBItem';
import SButton from '../components/SButton';
import { ElementsText, window } from '../constants';

const PAGE_WIDTH = window.width;

function Index() {
const [data, setData] = React.useState([...new Array(6).keys()]);
const [isVertical, setIsVertical] = React.useState(false);
const [isFast, setIsFast] = React.useState(false);
const [isAutoPlay, setIsAutoPlay] = React.useState(false);
const ref = React.useRef<ICarouselInstance>(null);

const baseOptions = isVertical
? ({
Expand All @@ -29,9 +31,11 @@ function Index() {
<Carousel
{...baseOptions}
loop
ref={ref}
autoPlay={isAutoPlay}
autoPlayInterval={isFast ? 100 : 2000}
data={[...new Array(6).keys()]}
data={data}
onSnapToItem={(index) => console.log('current index:', index)}
renderItem={({ index }) => <SBItem key={index} index={index} />}
/>
<SButton
Expand All @@ -55,6 +59,24 @@ function Index() {
>
{ElementsText.AUTOPLAY}:{`${isAutoPlay}`}
</SButton>
<SButton
onPress={() => {
console.log(ref.current?.getCurrentIndex());
}}
>
Log current index
</SButton>
<SButton
onPress={() => {
setData(
data.length === 6
? [...new Array(8).keys()]
: [...new Array(6).keys()]
);
}}
>
Change data length to:{data.length === 6 ? 8 : 6}
</SButton>
</View>
);
}
Expand Down
70 changes: 41 additions & 29 deletions src/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import React from 'react';
import Animated, { runOnJS, useDerivedValue } from 'react-native-reanimated';
import Animated, {
runOnJS,
runOnUI,
useDerivedValue,
} from 'react-native-reanimated';

import { useCarouselController } from './hooks/useCarouselController';
import { useAutoPlay } from './hooks/useAutoPlay';
Expand Down Expand Up @@ -74,58 +78,72 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
const carouselController = useCarouselController({
loop,
size,
data,
autoFillData,
handlerOffsetX,
length: data.length,
disable: !data.length,
withAnimation,
originalLength: data.length,
defaultIndex,
onScrollEnd: () => runOnJS(_onScrollEnd)(),
onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
onChange: (i) => !!onSnapToItem && runOnJS(onSnapToItem)(i),
duration: scrollAnimationDuration,
});

const {
sharedIndex,
sharedPreIndex,
to,
next,
prev,
sharedPreIndex,
sharedIndex,
computedIndex,
scrollTo,
getCurrentIndex,
} = carouselController;

const { start, pause } = useAutoPlay({
const { start: startAutoPlay, pause: pauseAutoPlay } = useAutoPlay({
autoPlay,
autoPlayInterval,
autoPlayReverse,
carouselController,
});

const _onScrollEnd = React.useCallback(() => {
computedIndex();
onScrollEnd?.(sharedPreIndex.current, sharedIndex.current);
}, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
'worklet';
const _sharedIndex = Math.round(sharedIndex.value);
const _sharedPreIndex = Math.round(sharedPreIndex.value);

if (onSnapToItem) {
runOnJS(onSnapToItem)(_sharedIndex);
}
if (onScrollEnd) {
runOnJS(onScrollEnd)(_sharedPreIndex, _sharedIndex);
}
}, [onSnapToItem, onScrollEnd, sharedIndex, sharedPreIndex]);

const scrollViewGestureOnScrollBegin = React.useCallback(() => {
pause();
pauseAutoPlay();
onScrollBegin?.();
}, [onScrollBegin, pause]);
}, [onScrollBegin, pauseAutoPlay]);

const scrollViewGestureOnScrollEnd = React.useCallback(() => {
start();
_onScrollEnd();
}, [_onScrollEnd, start]);
startAutoPlay();
/**
* TODO magic
*/
runOnUI(_onScrollEnd)();
}, [_onScrollEnd, startAutoPlay]);

const scrollViewGestureOnTouchBegin = React.useCallback(pause, [pause]);
const scrollViewGestureOnTouchBegin = React.useCallback(pauseAutoPlay, [
pauseAutoPlay,
]);

const scrollViewGestureOnTouchEnd = React.useCallback(start, [start]);
const scrollViewGestureOnTouchEnd = React.useCallback(startAutoPlay, [
startAutoPlay,
]);

const goToIndex = React.useCallback(
(i: number, animated?: boolean) => {
carouselController.to(i, animated);
to(i, animated);
},
[carouselController]
[to]
);

React.useImperativeHandle(
Expand All @@ -135,15 +153,9 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
prev,
getCurrentIndex,
goToIndex,
scrollTo: carouselController.scrollTo,
scrollTo,
}),
[
getCurrentIndex,
goToIndex,
next,
prev,
carouselController.scrollTo,
]
[getCurrentIndex, goToIndex, next, prev, scrollTo]
);

const visibleRanges = useVisibleRanges({
Expand Down
16 changes: 7 additions & 9 deletions src/ScrollViewGesture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,22 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
const _withSpring = React.useCallback(
(toValue: number, onFinished?: () => void) => {
'worklet';
const callback = (isFinished: boolean) => {
'worklet';
if (isFinished) {
onFinished && runOnJS(onFinished)();
}
};

const defaultWithAnimation: WithTimingAnimation = {
type: 'timing',
config: {
duration: scrollAnimationDuration,
duration: scrollAnimationDuration + 100,
easing: Easing.easeOutQuart,
},
};

return dealWithAnimation(withAnimation ?? defaultWithAnimation)(
toValue,
callback
(isFinished: boolean) => {
'worklet';
if (isFinished) {
onFinished && runOnJS(onFinished)();
}
}
);
},
[scrollAnimationDuration, withAnimation]
Expand Down
7 changes: 4 additions & 3 deletions src/hooks/useAutoPlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function useAutoPlay(opts: {
carouselController,
} = opts;

const { prev, next } = carouselController;
const timer = React.useRef<NodeJS.Timer>();
const stopped = React.useRef<boolean>(!autoPlay);

Expand All @@ -25,10 +26,10 @@ export function useAutoPlay(opts: {
timer.current && clearTimeout(timer.current);
timer.current = setTimeout(() => {
autoPlayReverse
? carouselController.prev({ onFinished: play })
: carouselController.next({ onFinished: play });
? prev({ onFinished: play })
: next({ onFinished: play });
}, autoPlayInterval);
}, [autoPlayReverse, autoPlayInterval, carouselController]);
}, [autoPlayReverse, autoPlayInterval, prev, next]);

const pause = React.useCallback(() => {
if (!autoPlay) {
Expand Down
Loading

0 comments on commit 9b03a4d

Please sign in to comment.