๐Ÿงญ 46. React Native Bottom Tab ๊ตฌ์กฐ์˜ ์ƒํƒœ ๊ด€๋ฆฌ ์ „๋žต โ€” ์ „ํ™˜ ์ดˆ๊ธฐํ™” ๋ฐฉ์ง€์™€ ์ƒํƒœ ๊ณต์œ ๊นŒ์ง€

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

React Native ์•ฑ์—์„œ
ํ•˜๋‹จ ํƒญ ๋„ค๋น„๊ฒŒ์ด์…˜(Bottom Tabs) ๊ตฌ์กฐ๋Š” ๊ฑฐ์˜ ๊ธฐ๋ณธ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ํƒญ ๊ฐ„ ์ด๋™์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค:

  • ํƒญ์„ ์ด๋™ํ–ˆ๋‹ค ๋Œ์•„์˜ค๋ฉด ํ™”๋ฉด์ด ๋‹ค์‹œ ๋ Œ๋”๋ง๋จ
  • ์Šคํฌ๋กค ์œ„์น˜๊ฐ€ ์ดˆ๊ธฐํ™”๋จ
  • ํƒญ ๊ฐ„ ๊ณตํ†ต ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ• ์ง€ ์• ๋งคํ•จ

์ด๋ฒˆ ๊ธ€์€ ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ
React Navigation์˜ ๊ตฌ์กฐ + ์ƒํƒœ๊ด€๋ฆฌ ์กฐํ•ฉ ์ „๋žต์„ ๋‹ค๋ฃฌ๋‹ค.


โœ… Bottom Tab ๊ธฐ๋ณธ ๊ตฌ์กฐ

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

function MainTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

โœ… ํ•˜๋‹จ ํƒญ ๊ตฌ์กฐ ๊ธฐ๋ณธ ๊ตฌํ˜„
โœ… ๊ฐ ํƒญ์€ ๋…๋ฆฝ๋œ ์Šคํƒ์ฒ˜๋Ÿผ ์ž‘๋™


โ— ํƒญ ์ด๋™ ์‹œ ์ƒํƒœ ์ดˆ๊ธฐํ™” ๋ฌธ์ œ

๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ ํƒญ์€ ๋ Œ๋”๋ง ์ƒํƒœ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€ํ•˜์ง€๋งŒ,
๊ฐ„ํ˜น ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ํ™”๋ฉด์ด ์ดˆ๊ธฐํ™”๋œ๋‹ค:

  • unmountOnBlur: true ์„ค์ • ์‹œ
  • useEffect์˜ ์˜์กด์„ฑ ์ฒ˜๋ฆฌ ๋ฏธํก
  • ์ƒํƒœ ์ €์žฅ์„ ๋กœ์ปฌ state๋กœ๋งŒ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ

โœ… ์ƒํƒœ ์œ ์ง€ ์ „๋žต 1: Zustand / Context ์‚ฌ์šฉ

๊ณตํ†ต๋œ ์ƒํƒœ๋Š” Zustand๋‚˜ Context๋กœ ๋ถ„๋ฆฌํ•ด์„œ ๊ด€๋ฆฌํ•˜๋ฉด
ํƒญ ๊ฐ„ ์ด๋™๊ณผ ๊ด€๊ณ„์—†์ด ์ƒํƒœ๊ฐ€ ์œ ์ง€๋œ๋‹ค.

const useFeedStore = create((set) => ({
  posts: [],
  setPosts: (posts) => set({ posts }),
}));
  • ํƒญ ์ด๋™ํ•ด๋„ ์ƒํƒœ ์œ ์ง€
  • ๋‹ค๋ฅธ ํƒญ์—์„œ๋„ ์ฝ๊ณ  ์“ฐ๊ธฐ ๊ฐ€๋Šฅ

โœ… ์ƒํƒœ ์œ ์ง€ ์ „๋žต 2: unmountOnBlur: false

<Tab.Screen
  name="Feed"
  component={FeedScreen}
  options={{ unmountOnBlur: false }}
/>
  • ํ•ด๋‹น ํƒญ์ด ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ ธ๋„ ์–ธ๋งˆ์šดํŠธ๋˜์ง€ ์•Š์Œ
  • ์ƒํƒœ ์œ ์ง€์™€ UX ์ผ๊ด€์„ฑ ํ™•๋ณด

๐Ÿ” ํƒญ ์•ˆ์— Stack์ด ์žˆ๋Š” ๊ตฌ์กฐ (์ค‘์ฒฉ ๊ตฌ์กฐ)

function FeedStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="FeedList" component={FeedList} />
      <Stack.Screen name="FeedDetail" component={FeedDetail} />
    </Stack.Navigator>
  );
}

<Tab.Navigator>
  <Tab.Screen name="Feed" component={FeedStack} />
</Tab.Navigator>

โœ… ์‹ค๋ฌด์—์„œ๋Š” ๊ฑฐ์˜ ํ•„์ˆ˜์ ์ธ ๊ตฌ์กฐ
โœ… ํƒญ๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ ํ™”๋ฉด ํ๋ฆ„ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ


๐Ÿ’ก ์‹ค์ „ ํŒ

์ƒํ™ฉํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
ํƒญ ์ด๋™ ์‹œ ํ™”๋ฉด ์ดˆ๊ธฐํ™”๋จunmountOnBlur: false
ํƒญ ๊ฐ„ ์ƒํƒœ ๊ณต์œ Zustand, Context
ํƒญ ์•ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ตฌ์„ฑStack ์ค‘์ฒฉ
์ƒํƒœ ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•  ๋•?useFocusEffect()๋กœ ์˜๋„์  ์ดˆ๊ธฐํ™” ์ฒ˜๋ฆฌ

๐Ÿง  ๋‚ด๊ฐ€ ๋А๋‚€ ์ 

์ฒ˜์Œ์—๋Š” ํƒญ ํ™”๋ฉด์ด ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋Š” ๊ฑธ ๋ณด๊ณ  โ€œ๋ฒ„๊ทธ์ธ๊ฐ€?โ€ ์‹ถ์—ˆ๋Š”๋ฐ,
์„ค์ • ํ•˜๋‚˜๋กœ ์œ ์ง€ ์—ฌ๋ถ€๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค๋Š” ๊ฑธ ์•Œ๊ณ  ๋‚˜์„ 
์˜๋„์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ์™€ ์œ ์ง€ํ•  ๋•Œ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์„ค๊ณ„ํ•˜๊ฒŒ ๋๋‹ค.

์ง€๊ธˆ์€ Zustand๋กœ ํƒญ ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ ,
unmountOnBlur๋กœ ํ™”๋ฉด ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ์ œ์–ดํ•˜๋ฉด์„œ
UX์™€ ํผํฌ๋จผ์Šค ๋‘˜ ๋‹ค ์ฑ™๊ธฐ๊ณ  ์žˆ๋‹ค.


๐Ÿงญ โ€œํƒญ ๊ฐ„ ์ด๋™์€ ๋‹จ์ˆœํ•œ UI๊ฐ€ ์•„๋‹ˆ๋ผ, ์‚ฌ์šฉ์ž ํ๋ฆ„์˜ ์ค‘์‹ฌ์ด๋‹ค.โ€


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

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