현재 프로젝트에서는 빠른 이미지 로딩과 캐싱, 그리고 안드로이드 고화질 이미지 로딩을 위해 react-native-fast-image 라이브러리를 사용 중이다.
해당 라이브러리의 이름에서부터 알 수 있듯이 빠른 이미지 로딩을 지원한다고는 하지만, 이미지의 용량이 크거나 인터넷이 약간 느린 경우 약간의 깜빡거림이 어쩔 수 없이 존재하기는 하다. 때문에 모든 이미지의 로딩 전에 해당 이미지가 로딩 중이라는 자리를 표시할 수 있는 일종의 skeleton 역할의 placeholder를 표시하도록 공통 컴포넌트를 작성하였다.
import React, { memo, useEffect, useState } from "react";
import { StyleSheet, View } from "react-native";
import FastImage, { FastImageProps } from "react-native-fast-image";
interface ImageLoaderProps extends FastImageProps {
height?: string | number;
width?: string | number;
useLoadingIndicator?: boolean;
loadingIndicatorHeight?: string | number;
loadingColor?: string;
}
/**
* FastImage 라이브러리를 사용하되 image placeholder를 구현하기 위해 분리한 컴포넌트.
* param으로 FastImageProps를 그대로 사용.
*/
const ImageLoader: React.FC<ImageLoaderProps> = ({
onLoadEnd,
loadingColor = "#DDDDDD",
source,
style,
...props
}) => {
const [isLoaded, setIsLoaded] = useState(false);
const [image, setImage] = useState(source);
useEffect(() => {
setImage(source);
}, [source]);
return (
<FastImage
{...props}
style={style}
source={image}
onLoadEnd={() => {
if (onLoadEnd) onLoadEnd();
setIsLoaded(true);
}}
>
{!isLoaded &&
<View style={[style, styles.defaultLoader, { backgroundColor: loadingColor }]} />
}
</FastImage>
);
};
export default memo(ImageLoader);
const styles = StyleSheet.create({
defaultLoader: { width: "200%", height: "200%", marginTop: "-50%", marginLeft: "-50%" },
});
onLoadEnd
prop을 통해 이미지의 로딩이 완료되는 시점을 캐치해서, 해당 시점 이전까지는 FastImage
의 children으로 특정 색을 표시하도록 작성하였다.
단, 이 경우 로컬에 존재하는 이미지와 같이 아주 빠르게 로딩이 되는 이미지를 표시할 때에도 부자연스러운 깜빡거림이 생긴다는 단점이 있어, 필요 시에는 loadingColor="transparent"
를 넘겨 깜빡거리지 않도록 사용하고 있다.