@@ -24,6 +24,9 @@ type ImageWithSizeLoadingProps = {
2424
2525 /** Invoked on mount and layout changes */
2626 onLayout ?: ( event : LayoutChangeEvent ) => void ;
27+
28+ /** Low-resolution URI shown as a placeholder while the full image loads */
29+ previewUri ?: string ;
2730} & ImageProps ;
2831
2932function ImageWithLoading ( {
@@ -37,12 +40,14 @@ function ImageWithLoading({
3740 onLoad,
3841 onLayout,
3942 style,
43+ previewUri,
4044 ...rest
4145} : ImageWithSizeLoadingProps ) {
4246 const styles = useThemeStyles ( ) ;
4347 const isLoadedRef = useRef < boolean | null > ( null ) ;
4448 const [ isImageCached , setIsImageCached ] = useState ( true ) ;
4549 const [ isLoading , setIsLoading ] = useState ( false ) ;
50+ const [ isThumbnailLoading , setIsThumbnailLoading ] = useState ( ! ! previewUri ) ;
4651 const { isOffline} = useNetwork ( ) ;
4752
4853 const handleError = ( ) => {
@@ -83,6 +88,21 @@ function ImageWithLoading({
8388 style = { [ styles . w100 , styles . h100 , containerStyles ] }
8489 onLayout = { onLayout }
8590 >
91+ { isLoading && ! ! previewUri && (
92+ // eslint-disable-next-line react-native-a11y/has-valid-accessibility-ignores-invert-colors -- Custom Image wrapper does not support this prop.
93+ < Image
94+ { ...rest }
95+ source = { { uri : previewUri } }
96+ style = { [ styles . w100 , styles . h100 , style ] }
97+ resizeMode = { resizeMode }
98+ onLoad = { ( e ) => {
99+ setIsThumbnailLoading ( false ) ;
100+ onLoad ?.( e ) ;
101+ } }
102+ loadingIconSize = { loadingIconSize }
103+ loadingIndicatorStyles = { loadingIndicatorStyles }
104+ />
105+ ) }
86106 { /* eslint-disable-next-line react-native-a11y/has-valid-accessibility-ignores-invert-colors -- Custom Image wrapper does not support this prop. */ }
87107 < Image
88108 { ...rest }
@@ -104,12 +124,13 @@ function ImageWithLoading({
104124 isLoadedRef . current = false ;
105125 setIsImageCached ( false ) ;
106126 setIsLoading ( true ) ;
127+ setIsThumbnailLoading ( ! ! previewUri ) ;
107128 waitForSession ?.( ) ;
108129 } }
109130 loadingIconSize = { loadingIconSize }
110131 loadingIndicatorStyles = { loadingIndicatorStyles }
111132 />
112- { isLoading && ! isImageCached && ! isOffline && (
133+ { isLoading && ( ! previewUri || isThumbnailLoading ) && ! isImageCached && ! isOffline && (
113134 < LoadingIndicator
114135 iconSize = { loadingIconSize }
115136 style = { [ styles . opacity1 , styles . bgTransparent , loadingIndicatorStyles ] }
0 commit comments