๐Ÿข 43. React Native ์ด๋ฏธ์ง€ Lazy Loading ์ „๋žต โ€” ํ™”๋ฉด ์ง„์ž… ์‹œ์  ๊ฐ์ง€๋ถ€ํ„ฐ ์ตœ์ ํ™”๊นŒ์ง€

JM_Devยท2025๋…„ 5์›” 28์ผ
0
post-thumbnail

์•ฑ์— ์ด๋ฏธ์ง€๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์„ฑ๋Šฅ์ด ๋š ๋–จ์–ด์ง€๊ณ ,
์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ๊ฐ„๋„ ๊ธธ์–ด์ง€๊ฒŒ ๋œ๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์ด ๋ฐ”๋กœ Lazy Loading, ์ฆ‰ ์ง€์—ฐ ๋กœ๋”ฉ์ด๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” React Native์—์„œ ์ด๋ฏธ์ง€ Lazy Loading์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š”
๊ฐ€์žฅ ์‹ค์šฉ์ ์ธ ๋ฐฉ์‹๋“ค์„ ์†Œ๊ฐœํ•œ๋‹ค.


โœ… ์™œ Lazy Loading์ด ์ค‘์š”ํ•œ๊ฐ€?

  • ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ํ•œ ๋ฒˆ์— ๋กœ๋”ฉํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€
  • ๋А๋ฆฐ ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ์—์„œ UX ์ €ํ•˜
  • FlatList ์Šคํฌ๋กค ์„ฑ๋Šฅ ์ €ํ•˜

Lazy Loading์€ "ํ™”๋ฉด์— ๋“ค์–ด์˜ค๊ธฐ ์ „๊นŒ์ง„ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š์Œ"์œผ๋กœ
์„ฑ๋Šฅ๊ณผ UX๋ฅผ ๋™์‹œ์— ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์ „๋žต์ด๋‹ค.


๐Ÿงฑ ๊ธฐ๋ณธ ๊ตฌ์กฐ โ€” FlatList + Viewability ๊ฐ์ง€

React Native์—๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ Intersection Observer๋Š” ์—†์ง€๋งŒ,
FlatList์˜ onViewableItemsChanged๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์œ ์‚ฌํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

<FlatList
  data={images}
  renderItem={renderItem}
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={{ itemVisiblePercentThreshold: 50 }}
/>
const onViewableItemsChanged = useRef(({ viewableItems }) => {
  const visibleIds = viewableItems.map((item) => item.item.id);
  setVisibleImageIds(visibleIds);
}).current;

โœ… ํ™”๋ฉด์— 50% ์ด์ƒ ๋ณด์ด๋Š” ์•„์ดํ…œ๋งŒ ๊ฐ์ง€ํ•ด์„œ
๋ Œ๋”๋ง ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ–ผ๏ธ LazyImage ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

function LazyImage({ uri, shouldLoad }) {
  if (!shouldLoad) {
    return <View style={{ width: 200, height: 200, backgroundColor: '#eee' }} />;
  }

  return (
    <Image
      source={{ uri }}
      style={{ width: 200, height: 200 }}
      resizeMode="cover"
    />
  );
}

๐Ÿ”„ ์ „์ฒด ์˜ˆ์‹œ ํ๋ฆ„

<FlatList
  data={data}
  renderItem={({ item }) => (
    <LazyImage
      uri={item.image}
      shouldLoad={visibleImageIds.includes(item.id)}
    />
  )}
  onViewableItemsChanged={onViewableItemsChanged}
/>
  • ์ด๋ฏธ์ง€๊ฐ€ ํ™”๋ฉด์— ๋ณด์ผ ๋•Œ๋งŒ ์‹ค์ œ <Image /> ๋ Œ๋”๋ง
  • ์Šค์ผˆ๋ ˆํ†ค ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋กœ UX ๋ณด์™„ ๊ฐ€๋Šฅ

โš™๏ธ ์ถ”๊ฐ€ ์ตœ์ ํ™” ํฌ์ธํŠธ

ํ•ญ๋ชฉ์ „๋žต
์บ์‹ฑreact-native-fast-image ์‚ฌ์šฉ (์ž๋™ ์บ์‹ฑ)
์ด๋ฏธ์ง€ ์••์ถ•์„œ๋ฒ„์—์„œ WebP, ์••์ถ• ๋ฒ„์ „ ์ œ๊ณต
๋””๋ฐ”์šด์‹ฑonViewableItemsChanged์— debounce ์ ์šฉ ๊ฐ€๋Šฅ
ํ•ด์ƒ๋„ ๋Œ€์‘@2x, @3x ๊ตฌ์„ฑ ํ•„์ˆ˜

๐Ÿ“ฑ ์‹ค์ „์—์„œ ๋А๋‚€ ์ 

FlatList์— 100์žฅ ๋„˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์„ ๋•Œ
๋ Œ๋”๋ง ์ง€์—ฐ์ด ์‹ฌํ–ˆ๊ณ , ์Šคํฌ๋กค๋„ ๋งŽ์ด ๋Š๊ฒผ๋‹ค.

๊ทธ๊ฑธ Lazy Loading์œผ๋กœ ๋ฐ”๊พธ๋‹ˆ๊นŒ
ํ™”๋ฉด ์ง„์ž… ์‹œ์ ์—๋งŒ ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋”ฉ๋˜์–ด
์Šคํฌ๋กค ์„ฑ๋Šฅ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์ ์œ ์œจ์ด ํฌ๊ฒŒ ๊ฐœ์„ ๋๋‹ค.

์ง€๊ธˆ์€ ๋ฌด์กฐ๊ฑด LazyImage ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด
๊ณตํ†ต ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ๋กœ ํ™œ์šฉํ•˜๊ณ  ์žˆ๋‹ค.


๐Ÿข โ€œ์„ฑ๋Šฅ์€ ๋น ๋ฅธ ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ, ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ค„์ด๋Š” ๋ฐ์„œ ๋‚˜์˜จ๋‹ค.โ€


profile
๊ฐœ๋ฐœ์ž๋กœ ์ทจ์—…์„ ์ค€๋น„ ์ค‘ ์ด๋ฉฐ, ์—ด์‹ฌํžˆ ๊ณต๋ถ€ ์ค‘ ์ž…๋‹ˆ๋‹ค!

0๊ฐœ์˜ ๋Œ“๊ธ€