Skip to content

Commit 263504d

Browse files
committed
fix: issue onPageChange call multiple times
1 parent ae6107f commit 263504d

File tree

4 files changed

+48
-28
lines changed

4 files changed

+48
-28
lines changed

example/src/App.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ export default function App() {
134134
currentPage={currentPage}
135135
containerStyle={{ marginTop: 20 }}
136136
activeIndicatorStyle={{
137-
width: 20,
138-
height: 10,
137+
height: 20,
139138
borderRadius: 5,
140139
}}
141140
indicatorConfigs={{
142141
spaceBetween: 10,
142+
indicatorWidth: 10,
143+
indicatorSelectedWidth: 20,
143144
}}
144145
/>
145146
</View>

src/components/Carousel.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,7 @@ function Carousel<TData>(
166166
animatedPage.value = actualPage;
167167
if (onPageChange) {
168168
onPageChange(actualPage);
169-
}
170-
currentPage.value = page;
169+
}
171170
if (!loop) return;
172171
if (page === pageItems.length - 1) {
173172
jumpTo(additionalPagesPerSide * 2 - 1);
@@ -189,6 +188,7 @@ function Carousel<TData>(
189188
if (expectedPosition.current === pageNum) {
190189
freeze.value = false;
191190
}
191+
currentPage.value = pageNum;
192192
runOnJS(handlePageChange)(pageNum);
193193
}
194194
},
@@ -220,12 +220,16 @@ function Carousel<TData>(
220220
}, []);
221221

222222
const beginDrag = useCallback(() => {
223-
setDragging(true);
224-
}, []);
223+
if (autoPlay) {
224+
setDragging(true);
225+
}
226+
}, [autoPlay]);
225227

226228
const endDrag = useCallback(() => {
227-
setTimeout(() => setDragging(false), 200);
228-
}, []);
229+
if (autoPlay) {
230+
setTimeout(() => setDragging(false), 200);
231+
}
232+
}, [autoPlay]);
229233

230234
const getItemKey = useCallback(
231235
(item: TData, index: number): string => {
@@ -257,24 +261,27 @@ function Carousel<TData>(
257261
[beginDrag, endDrag, refreshPage]
258262
);
259263

260-
function renderPage(item: TData, i: number) {
261-
const containerStyle = useMemo(() => {
264+
const containerStyle = useCallback(
265+
(index: number) => {
262266
if (firstItemAlignment === 'start') {
263267
return {
264-
paddingLeft: i === 0 ? 0 : spaceBetween / 2,
265-
paddingRight: i === data.length - 1 ? 0 : spaceBetween / 2,
268+
paddingLeft: index === 0 ? 0 : spaceBetween / 2,
269+
paddingRight: index === data.length - 1 ? 0 : spaceBetween / 2,
266270
};
267271
}
268272
return {
269273
paddingLeft: spaceBetween / 2,
270274
paddingRight: spaceBetween / 2,
271275
};
272-
}, [spaceBetween, firstItemAlignment]);
276+
},
277+
[spaceBetween, firstItemAlignment]
278+
);
273279

280+
function renderPage(item: TData, i: number) {
274281
return (
275282
<PageItem
276283
key={getItemKey(item, i)}
277-
containerStyle={containerStyle}
284+
containerStyle={containerStyle(i)}
278285
item={item}
279286
index={i}
280287
offset={offsets[i]}

src/components/PaginationIndicator.tsx

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
/* eslint-disable @typescript-eslint/ban-ts-comment */
12
import React, { useCallback, useMemo } from 'react';
23
import { View, StyleSheet, ViewStyle } from 'react-native';
34
import Animated, {
45
useAnimatedStyle,
56
useDerivedValue,
67
withSpring,
78
} from 'react-native-reanimated';
8-
import type { PaginationProps } from '../types';
9+
import type { IndicatorConfigs, PaginationProps } from '../types';
910

10-
const defaultIndicatorConfigs = {
11+
const defaultIndicatorConfigs: IndicatorConfigs = {
1112
indicatorColor: 'gray',
12-
indicatorSelectedColor: 'blue',
1313
indicatorWidth: 6,
14+
indicatorSelectedColor: 'blue',
15+
indicatorSelectedWidth: 6,
1416
spaceBetween: 3,
1517
};
1618

@@ -54,7 +56,7 @@ export default function PaginationIndicator({
5456

5557
const translateX = useDerivedValue(() => {
5658
return withSpring(
57-
currentPage.value * (configs.indicatorWidth + configs.spaceBetween),
59+
currentPage.value * (configs.indicatorWidth! + configs.spaceBetween!),
5860
defaultSpringConfig
5961
);
6062
}, []);
@@ -70,10 +72,18 @@ export default function PaginationIndicator({
7072
}, []);
7173

7274
const renderItem = useCallback((pageNumber: number) => {
75+
// @ts-ignore
76+
if (activeIndicatorStyle?.width) {
77+
console.error("Do not use activeIndicatorStyle: { width }. Please use indicatorConfigs: { indicatorSelectedWidth } instead");
78+
}
79+
// @ts-ignore
80+
if (indicatorStyle?.width) {
81+
console.error("Do not use indicatorStyle: { width }. Please use indicatorConfigs: { indicatorWidth } instead");
82+
}
7383
const dotContainerStyle: ViewStyle = StyleSheet.flatten([
7484
styles.dotContainer,
7585
{
76-
width: configs.indicatorWidth,
86+
width: configs.indicatorSelectedWidth,
7787
height: configs.indicatorWidth,
7888
marginEnd: configs.spaceBetween,
7989
},
@@ -87,18 +97,19 @@ export default function PaginationIndicator({
8797
{
8898
width: configs.indicatorWidth,
8999
height: configs.indicatorWidth,
90-
borderRadius: configs.indicatorWidth / 2,
100+
borderRadius: configs.indicatorWidth! / 2,
91101
backgroundColor: configs.indicatorColor,
92102
},
93103
indicatorStyle,
94104
]);
95105

106+
console.log(configs);
107+
108+
96109
const aStyle = useAnimatedStyle(() => {
97110
return {
98111
width: withSpring(
99-
currentPage.value === pageNumber
100-
? (dotContainerStyle.width as number || configs.indicatorWidth)
101-
: (dotStyle.width as number || configs.indicatorWidth),
112+
currentPage.value === pageNumber ? configs.indicatorSelectedWidth! : configs.indicatorWidth!,
102113
defaultSpringConfig
103114
),
104115
};
@@ -120,9 +131,9 @@ export default function PaginationIndicator({
120131
style={[
121132
styles.dotSelectedStyle,
122133
{
123-
width: configs.indicatorWidth,
134+
width: configs.indicatorSelectedWidth,
124135
height: configs.indicatorWidth,
125-
borderRadius: configs.indicatorWidth / 2,
136+
borderRadius: configs.indicatorWidth! / 2,
126137
backgroundColor: configs.indicatorSelectedColor,
127138
},
128139
activeIndicatorStyle,

src/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ export type PaginationProps = {
4747
totalPage: number;
4848
currentPage: Animated.SharedValue<number>;
4949
containerStyle?: StyleProp<ViewStyle>;
50-
indicatorStyle?: StyleProp<ViewStyle>;
51-
activeIndicatorStyle?: StyleProp<ViewStyle>;
50+
indicatorStyle?: Omit<StyleProp<ViewStyle>, 'width'>;
51+
activeIndicatorStyle?: Omit<StyleProp<ViewStyle>, 'width'>;
5252
indicatorConfigs?: IndicatorConfigs;
5353
};
5454

5555
export type IndicatorConfigs = {
5656
indicatorColor?: string;
57-
indicatorSelectedColor?: string;
5857
indicatorWidth?: number;
58+
indicatorSelectedColor?: string;
59+
indicatorSelectedWidth?: number;
5960
spaceBetween?: number;
6061
};

0 commit comments

Comments
 (0)