Skip to content

Commit

Permalink
fix: refactoring logic of withAutoFillData, Add onProgressChange valu…
Browse files Browse the repository at this point in the history
…e boundary

fix #158
  • Loading branch information
dohooo committed May 2, 2022
1 parent 4076edb commit 101456a
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 34 deletions.
28 changes: 18 additions & 10 deletions src/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { useVisibleRanges } from './hooks/useVisibleRanges';

import type { ICarouselInstance, TCarouselProps } from './types';
import { StyleSheet, View } from 'react-native';
import { DATA_LENGTH } from './constants';
import { BaseLayout } from './layouts/BaseLayout';
import { useLayoutConfig } from './hooks/useLayoutConfig';
import { useInitProps } from './hooks/useInitProps';
import { CTX } from './store';
import { useCommonVariables } from './hooks/useCommonVariables';
import { useOnProgressChange } from './hooks/useOnProgressChange';
import { computedRealIndexWithAutoFillData } from './utils/computedWithAutoFillData';

const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
(_props, ref) => {
Expand All @@ -25,6 +25,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
data,
rawData,
loop,
autoFillData,
mode,
style,
width,
Expand Down Expand Up @@ -60,7 +61,14 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
}, [loop, size, dataLength]);

usePropsErrorBoundary(props);
useOnProgressChange({ size, offsetX, rawData, onProgressChange });
useOnProgressChange({
autoFillData,
loop,
size,
offsetX,
rawData,
onProgressChange,
});

const carouselController = useCarouselController({
loop,
Expand Down Expand Up @@ -148,14 +156,12 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(

const renderLayout = React.useCallback(
(item: any, i: number) => {
let realIndex = i;
if (rawData.length === DATA_LENGTH.SINGLE_ITEM) {
realIndex = i % 1;
}

if (rawData.length === DATA_LENGTH.DOUBLE_ITEM) {
realIndex = i % 2;
}
const realIndex = computedRealIndexWithAutoFillData({
index: i,
dataLength: rawData.length,
loop,
autoFillData,
});

return (
<BaseLayout
Expand All @@ -176,9 +182,11 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
);
},
[
loop,
rawData,
offsetX,
visibleRanges,
autoFillData,
renderItem,
layoutConfig,
customAnimation,
Expand Down
27 changes: 13 additions & 14 deletions src/hooks/useInitProps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { computedFillDataWithAutoFillData } from '@/utils/computedWithAutoFillData';
import React from 'react';
import { DATA_LENGTH } from '../constants';
import type { TCarouselProps } from '../types';

type TGetRequiredProps<P extends keyof TCarouselProps> = Record<
Expand All @@ -15,6 +15,7 @@ export type TInitializeCarouselProps<T> = TCarouselProps<T> &
| 'height'
| 'scrollAnimationDuration'
| 'autoPlayInterval'
| 'autoFillData'
> & {
// Raw data that has not been processed
rawData: T[];
Expand Down Expand Up @@ -43,19 +44,16 @@ export function useInitProps<T>(
const height = Math.round(_height || 0);
const autoPlayInterval = Math.max(_autoPlayInterval, 0);

const data = React.useMemo<T[]>(() => {
if (!loop || !autoFillData) return rawData;

if (rawData.length === DATA_LENGTH.SINGLE_ITEM) {
return [rawData[0], rawData[0], rawData[0]];
}

if (rawData.length === DATA_LENGTH.DOUBLE_ITEM) {
return [rawData[0], rawData[1], rawData[0], rawData[1]];
}

return rawData;
}, [rawData, loop, autoFillData]);
const data = React.useMemo<T[]>(
() =>
computedFillDataWithAutoFillData<T>({
loop,
autoFillData,
data: rawData,
dataLength: rawData.length,
}),
[rawData, loop, autoFillData]
);

if (props.mode === 'vertical-stack' || props.mode === 'horizontal-stack') {
if (!props.modeConfig) {
Expand All @@ -67,6 +65,7 @@ export function useInitProps<T>(
return {
...props,
defaultIndex,
autoFillData,
data,
rawData,
loop,
Expand Down
30 changes: 20 additions & 10 deletions src/hooks/useOnProgressChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,39 @@ import Animated, {
runOnJS,
useAnimatedReaction,
} from 'react-native-reanimated';
import { DATA_LENGTH } from '../constants';
import { computedOffsetXValueWithAutoFillData } from '@/utils/computedWithAutoFillData';
import type { TCarouselProps } from '../types';

export function useOnProgressChange(
opts: {
size: number;
autoFillData: boolean;
loop: boolean;
offsetX: Animated.SharedValue<number>;
rawData: TCarouselProps['data'];
} & Pick<TCarouselProps, 'onProgressChange'>
) {
const { offsetX, rawData, size, onProgressChange } = opts;
const { autoFillData, loop, offsetX, rawData, size, onProgressChange } =
opts;

const rawDataLength = rawData.length;

useAnimatedReaction(
() => offsetX.value,
(_value) => {
let value = _value;

if (rawDataLength === DATA_LENGTH.SINGLE_ITEM) {
value = value % size;
}
let value = computedOffsetXValueWithAutoFillData({
value: _value,
rawDataLength,
size,
autoFillData,
loop,
});

if (rawDataLength === DATA_LENGTH.DOUBLE_ITEM) {
value = value % (size * 2);
if (!loop) {
value = Math.max(
-((rawDataLength - 1) * size),
Math.min(value, 0)
);
}

let absoluteProgress = Math.abs(value / size);
Expand All @@ -36,6 +46,6 @@ export function useOnProgressChange(
!!onProgressChange &&
runOnJS(onProgressChange)(value, absoluteProgress);
},
[onProgressChange, rawDataLength]
[loop, autoFillData, rawDataLength, onProgressChange]
);
}
76 changes: 76 additions & 0 deletions src/utils/computedWithAutoFillData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { DATA_LENGTH } from 'src/constants';

const { SINGLE_ITEM, DOUBLE_ITEM } = DATA_LENGTH;

function isAutoFillData(params: { autoFillData: boolean; loop: boolean }) {
'worklet';
return !!params.loop && !!params.autoFillData;
}

type BaseParams<T extends object = {}> = {
autoFillData: boolean;
loop: boolean;
} & T;

export function computedOffsetXValueWithAutoFillData(
params: BaseParams<{
rawDataLength: number;
value: number;
size: number;
}>
) {
'worklet';

const { rawDataLength, value, size, loop, autoFillData } = params;

if (isAutoFillData({ loop, autoFillData })) {
switch (rawDataLength) {
case SINGLE_ITEM:
return value % size;
case DOUBLE_ITEM:
return value % (size * 2);
}
}

return value;
}

export function computedRealIndexWithAutoFillData(
params: BaseParams<{
index: number;
dataLength: number;
}>
) {
const { index, dataLength, loop, autoFillData } = params;

if (isAutoFillData({ loop, autoFillData })) {
switch (dataLength) {
case SINGLE_ITEM:
return index % 1;
case DOUBLE_ITEM:
return index % 2;
}
}

return index;
}

export function computedFillDataWithAutoFillData<T>(
params: BaseParams<{
data: T[];
dataLength: number;
}>
): T[] {
const { data, loop, autoFillData, dataLength } = params;

if (isAutoFillData({ loop, autoFillData })) {
switch (dataLength) {
case SINGLE_ITEM:
return [data[0], data[0], data[0]];
case DOUBLE_ITEM:
return [data[0], data[1], data[0], data[1]];
}
}

return data;
}

0 comments on commit 101456a

Please sign in to comment.