For AI agents: the complete documentation index is available at /2.x/ko/llms.txt, the full documentation bundle is available at /2.x/ko/llms-full.txt, and this page is available as Markdown at /2.x/ko/guide/performance-optimization-tips.md.
v3 정식 출시. 변경 사항 보기
  • 한국어
  • 2.x
  • 성능 최적화 팁

    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-imageFastImage 사용을 권장합니다.

    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>
      );
    }

    디바이스에서 테스트하세요. (시뮬레이터에서는 성능이 제한될 수 있습니다.)