Skip to content

Commit

Permalink
perf: reduce the calculation of animation values
Browse files Browse the repository at this point in the history
  • Loading branch information
gxxgcn committed Dec 7, 2021
1 parent 137cb90 commit de32274
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 16 deletions.
10 changes: 10 additions & 0 deletions src/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useCarouselController } from './hooks/useCarouselController';
import { useAutoPlay } from './hooks/useAutoPlay';
import { useIndexController } from './hooks/useIndexController';
import { usePropsErrorBoundary } from './hooks/usePropsErrorBoundary';
import { useVisibleRanges } from './hooks/useVisibleRanges';

const defaultSpringConfig: Animated.WithSpringConfig = {
damping: 100,
Expand Down Expand Up @@ -379,6 +380,12 @@ function Carousel<T extends unknown = any>(
[getCurrentIndex, goToIndex, next, prev]
);

const visibleRanges = useVisibleRanges({
total: data.length,
viewSize: width,
translation: handlerOffsetX,
});

const renderLayout = React.useCallback(
(item: T, i: number) => {
switch (mode) {
Expand All @@ -393,6 +400,7 @@ function Carousel<T extends unknown = any>(
index={i}
key={i}
loop={loop}
visibleRanges={visibleRanges}
>
{renderItem(item, i)}
</ParallaxLayout>
Expand All @@ -407,6 +415,7 @@ function Carousel<T extends unknown = any>(
index={i}
key={i}
loop={loop}
visibleRanges={visibleRanges}
>
{renderItem(item, i)}
</CarouselItem>
Expand All @@ -423,6 +432,7 @@ function Carousel<T extends unknown = any>(
parallaxScrollingScale,
width,
renderItem,
visibleRanges,
]
);

Expand Down
20 changes: 13 additions & 7 deletions src/CarouselItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { FlexStyle, View } from 'react-native';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';
import { useOffsetX } from './hooks/useOffsetX';
import type { IVisibleRanges } from './hooks/useVisibleRanges';

export const CarouselItem: React.FC<{
loop?: boolean;
Expand All @@ -10,6 +11,7 @@ export const CarouselItem: React.FC<{
width: number;
data: unknown[];
height?: FlexStyle['height'];
visibleRanges: IVisibleRanges;
}> = (props) => {
const {
handlerOffsetX,
Expand All @@ -19,15 +21,19 @@ export const CarouselItem: React.FC<{
height = '100%',
loop,
data,
visibleRanges,
} = props;

const x = useOffsetX({
handlerOffsetX,
index,
width,
data,
loop,
});
const x = useOffsetX(
{
handlerOffsetX,
index,
width,
data,
loop,
},
visibleRanges
);

const offsetXStyle = useAnimatedStyle(() => {
return {
Expand Down
14 changes: 12 additions & 2 deletions src/hooks/useOffsetX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Animated, {
interpolate,
useDerivedValue,
} from 'react-native-reanimated';
import type { IVisibleRanges } from './useVisibleRanges';

interface IOpts {
index: number;
Expand All @@ -14,7 +15,7 @@ interface IOpts {
loop?: boolean;
}

export const useOffsetX = (opts: IOpts) => {
export const useOffsetX = (opts: IOpts, visibleRanges: IVisibleRanges) => {
const {
handlerOffsetX,
index,
Expand All @@ -30,6 +31,15 @@ export const useOffsetX = (opts: IOpts) => {
const HALF_WIDTH = 0.5 * width;

const x = useDerivedValue(() => {
function inRange(i: number, range: number[]) {
return i >= range[0] && i <= range[1];
}
if (
!inRange(index, visibleRanges.value.negativeRange) &&
!inRange(index, visibleRanges.value.positiveRange)
) {
return Number.MAX_SAFE_INTEGER;
}
if (loop) {
const positiveCount =
type === 'positive' ? viewCount : VALID_LENGTH - viewCount;
Expand Down Expand Up @@ -71,7 +81,7 @@ export const useOffsetX = (opts: IOpts) => {
}

return handlerOffsetX.value + width * index;
}, [loop, data, viewCount, type]);
}, [loop, data, viewCount, type, visibleRanges]);

return x;
};
47 changes: 47 additions & 0 deletions src/hooks/useVisibleRanges.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type Animated from 'react-native-reanimated';
import { useDerivedValue } from 'react-native-reanimated';

export type IVisibleRanges = Animated.SharedValue<{
negativeRange: number[];
positiveRange: number[];
}>;

export function useVisibleRanges(options: {
total: number;
viewSize: number;
positiveCount?: number;
negativeCount?: number;
translation: Animated.SharedValue<number>;
}): IVisibleRanges {
const {
total,
viewSize,
positiveCount = 1,
negativeCount = 1,
translation,
} = options;

const ranges = useDerivedValue(() => {
let curIndex = Math.round(-translation.value / viewSize);
curIndex = curIndex < 0 ? (curIndex % total) + total : curIndex;
const negativeRange = [
(curIndex - negativeCount + total) % total,
(curIndex - 1 + total) % total,
];
const positiveRange = [
(curIndex + total) % total,
(curIndex + positiveCount + total) % total,
];
if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
negativeRange[1] = total - 1;
positiveRange[0] = 0;
}
if (positiveRange[0] > positiveRange[1]) {
negativeRange[1] = total - 1;
positiveRange[0] = 0;
}
return { negativeRange, positiveRange };
}, [positiveCount, positiveCount, total, translation]);

return ranges;
}
20 changes: 13 additions & 7 deletions src/layouts/ParallaxLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Animated, {
useAnimatedStyle,
} from 'react-native-reanimated';
import { useOffsetX } from '../hooks/useOffsetX';
import type { IVisibleRanges } from '../hooks/useVisibleRanges';

export const ParallaxLayout: React.FC<{
loop?: boolean;
Expand All @@ -16,6 +17,7 @@ export const ParallaxLayout: React.FC<{
index: number;
width: number;
data: unknown[];
visibleRanges: IVisibleRanges;
}> = (props) => {
const {
handlerOffsetX,
Expand All @@ -26,15 +28,19 @@ export const ParallaxLayout: React.FC<{
loop,
data,
children,
visibleRanges,
} = props;

const x = useOffsetX({
handlerOffsetX,
index,
width,
data,
loop,
});
const x = useOffsetX(
{
handlerOffsetX,
index,
width,
data,
loop,
},
visibleRanges
);

const offsetXStyle = useAnimatedStyle(() => {
const baseTranslateX = x.value - index * width;
Expand Down

0 comments on commit de32274

Please sign in to comment.