Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 5x 5x 5x 1x 1x 5x 1x 1x 1x 5x 1x 1x 4x | import { useCallback, useState } from 'react';
import { Image, ImageSourcePropType, ImageStyle, StyleProp, DimensionValue } from 'react-native';
import { YStack } from 'tamagui';
import { neutralScale } from '@/src/design-system/tokens';
import { Skeleton } from './Skeleton';
interface LazyImageProps {
source: ImageSourcePropType;
width: DimensionValue;
height: DimensionValue;
borderRadius?: number;
resizeMode?: 'cover' | 'contain' | 'stretch' | 'center';
placeholder?: ImageSourcePropType;
style?: StyleProp<ImageStyle>;
showSkeleton?: boolean;
onLoad?: () => void;
onError?: () => void;
testID?: string;
}
export function LazyImage({
source,
width,
height,
borderRadius = 0,
resizeMode = 'cover',
placeholder,
style,
showSkeleton = true,
onLoad,
onError,
testID,
}: LazyImageProps) {
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
const handleLoad = useCallback(() => {
setIsLoading(false);
onLoad?.();
}, [onLoad]);
const handleError = useCallback(() => {
setIsLoading(false);
setHasError(true);
onError?.();
}, [onError]);
if (hasError) {
Iif (placeholder) {
return (
<Image
source={placeholder}
style={[{ width, height, borderRadius }, style]}
resizeMode={resizeMode}
testID={testID}
/>
);
}
return (
<YStack
width={width}
height={height}
backgroundColor={neutralScale.neutral2}
borderRadius={borderRadius}
alignItems="center"
justifyContent="center"
testID={testID}
>
{/* Optionally, you can add an error icon or text here */}
</YStack>
);
}
return (
<YStack
width={width as any}
height={height as any}
borderRadius={borderRadius}
overflow="hidden"
testID="lazy-image-container"
>
{showSkeleton && isLoading && (
<Skeleton width={width as any} height={height as any} borderRadius={borderRadius} />
)}
<Image
source={source}
style={[
{ width, height, borderRadius },
isLoading ? { opacity: 0 } : { opacity: 1 },
style,
]}
resizeMode={resizeMode}
onLoad={handleLoad}
onError={handleError}
testID={testID}
/>
</YStack>
);
}
export async function preloadImage(uri: string): Promise<boolean> {
return new Promise((resolve) => {
Image.prefetch(uri)
.then(() => resolve(true))
.catch(() => resolve(false));
});
}
export async function preloadImages(uris: string[]): Promise<boolean[]> {
return Promise.all(uris.map(preloadImage));
}
|