#성능 최적화 팁
#renderItem 함수는 useCallback으로 감싸서 불필요한 리렌더링을 방지하세요.
import { useCallback, useState } from 'react';
import { ScrollView, Image, Modal } from 'react-native';
import { GestureViewer } from 'react-native-gesture-image-viewer';
const images = [...];
function App() {
const [visible, setVisible] = useState(false);
const renderImage = useCallback((imageUrl: string) => {
return <Image source={{ uri: imageUrl }} style={{ width: '100%', height: '100%' }} resizeMode="contain" />;
}, []);
return (
<Modal visible={visible} onRequestClose={() => setVisible(false)}>
<GestureViewer
data={images}
renderItem={renderImage}
ListComponent={ScrollView}
onDismiss={() => setVisible(false)}
/>
</Modal>
);
}#변경되지 않은 data를 다시 만들지 마세요.
목록 내용이 바뀔 때 새 배열을 전달하는 것은 올바른 사용법이며 정상적으로 지원됩니다. 다만 부모 컴포넌트가 자주 rerender될 때 동일한 배열을 매번 다시 만들면 viewer와 치수 조정 작업이 반복될 수 있습니다. 변환이 필요하지 않다면 기존 배열을 그대로 전달하고, 실제 파생 데이터만 메모이제이션하세요.
import { useMemo } from 'react';
// ❌ 지양: 렌더링할 때마다 새 배열을 만듭니다.
<GestureViewer data={[...images]} renderItem={renderImage} />
// ✅ 권장: 내용이 바뀌지 않았다면 기존 prop 또는 state 값을 그대로 사용합니다.
<GestureViewer data={images} renderItem={renderImage} />
// ✅ 변환이 필요하다면 원본 값을 기준으로 파생 배열을 메모이제이션합니다.
function LimitedGallery({ images }: { images: string[] }) {
const visibleImages = useMemo(
() => images.slice(0, 20),
[images],
);
return <GestureViewer data={visibleImages} renderItem={renderImage} />;
}data를 제자리에서 변경하지 말고, 내용이 바뀔 때 배열을 교체하세요.
// ❌ 지양
images.push(nextImage);
setImages(images);
// ✅ 권장
setImages((currentImages) => [...currentImages, nextImage]);#대용량 이미지의 경우 expo-image나 FastImage 사용을 권장합니다.
import { useCallback, useState } from 'react';
import { ScrollView, Modal } from 'react-native';
import { GestureViewer } from 'react-native-gesture-image-viewer';
import { Image } from 'expo-image';
const images = [...];
function App() {
const [visible, setVisible] = useState(false);
const renderImage = useCallback((imageUrl: string) => {
return (
<Image
source={{ uri: imageUrl }}
style={{ width: '100%', height: '100%' }}
contentFit="contain"
/>
);
}, []);
return (
<Modal visible={visible} onRequestClose={() => setVisible(false)}>
<GestureViewer
data={images}
renderItem={renderImage}
ListComponent={ScrollView}
onDismiss={() => setVisible(false)}
/>
</Modal>
);
}#많은 수의 이미지를 다룰 때는 FlashList 사용을 권장합니다.
import { useCallback, useState } from 'react';
import { Image, Modal } from 'react-native';
import { GestureViewer } from 'react-native-gesture-image-viewer';
import { FlashList } from '@shopify/flash-list';
const images = [...];
function App() {
const [visible, setVisible] = useState(false);
const renderImage = useCallback((imageUrl: string) => {
return <Image source={{ uri: imageUrl }} style={{ width: '100%', height: '100%' }} resizeMode="contain" />;
}, []);
return (
<Modal visible={visible} onRequestClose={() => setVisible(false)}>
<GestureViewer
data={images}
renderItem={renderImage}
ListComponent={FlashList}
onDismiss={() => setVisible(false)}
/>
</Modal>
);
}