My Boundary As Much As I Experienced

ReactNative) React Navigation으로 다른 Screen으로 이동 후 스크롤링 하기 본문

FrontEnd/React Native

ReactNative) React Navigation으로 다른 Screen으로 이동 후 스크롤링 하기

Bumang 2024. 5. 28. 19:52

 

리액트 네이티브에서 주로 쓰는 router은 React Navigation이다.

React Navigation으로 다른 페이지로 이동하는 방법을 알아보고,

추가로 스크롤을 원하는 곳으로 내리는 방법을 알아보자

 

Navigating 하는 법

 

간단하다. Navigation을 import해서 navigation 객체를 만들어준다.

import { useNavigation } from '@react-navigation/native';

const navigation = useNavigation();

 

핸들러를 만들고 거기서 navigation의 navigate 메소드를 활용해서 가고 싶은 곳으로 가게 하라.

그런데 이때 주의해야될게 있다.

 

당신의 프로젝트 구조가 어떻게 될지는 모르겠는데,

보통 모바일 앱은 BottomTab들이 있고 그 안에 탭별로 stack이 또 있는 구조이다.

nested된 route로 구성되어 있는 것이다.

 

내 프로젝트 또한 그렇다. 그리고 nested된 구조라면, 아래와 같이 사용해야된다.

    const handleNavigatePoke = useCallback(async () => {
        navigation.navigate('Main', {
            screen: 'BottomTab',
            params: {
                screen: 'Shop',
            }
        });
    }, []);

 

설명하자면 당연히도 navigation은 루트단부터 시작해야 경로를 알아먹는다.

navigate는 screen과 params라는 패러미터를 받을 수 있는데,

 

- screen이 목적지(혹은 경유지)라고 보면 된다.

- params는 추가로 가져갈 상태라고 보면 된다.

 

당신이 원하는대로 params 속성을 구성할 수 있다. (userId, order, message, ..., hoola)

 

Navigating in Nested routes

그러나 params 안에서도 'screen'과 'params'라는 이름을 또 쓰면,

현재 위치 기준에서 또 다른 경로로 이동하면서 패러미터를 가져갈 수 있게 되는 것이다.

 

(그러니 screen과 params는 navigate메소드의 예약 속성이라고도 할 수 있다.)

 

 

마지막으로 onPress든 뭐든 이벤트 핸들러로 연결만 시켜주면 된다.

// 어김없이 onPress에 핸들러 장착
<TouchableOpacity onPress={handleNavigatePoke}>
  <Text style={styles.pokeDescriptionText}>Shop</Text>
</TouchableOpacity>

 

 

 

그리고 이걸 통해 특정 파트로 스크롤을 내리려면?

아까 말한 nested routes에서 navigating하는 방법을 통해 원하는 페이지까지 도달한 후,

임의의 속성 section을 만들어 도달할 곳을 설정해준다. (Poke라는 아이템이 있는  곳까지 가게 할 예정)

    const handleNavigatePoke = useCallback(async () => {
        navigation.navigate('Main', {
            screen: 'BottomTab',
            params: {
                screen: 'Shop',
                params: {
                    // 개발자가 임의로 설정한 state, not 예약 속성
                    section: 'Poke'
                }
            }
        });
    }, []);

 

이렇게 설정한 다음에 전체 Navigation 관리하는 곳 (보통 App.tsx)에서

section의 초기값을 설정해줘야 한다.

// App.tsx의 navigation 설정 부분...
// section
<BottomTab.Screen
  name="Shop"
  component={ShopScreen}
  options={{
    title: 'Shop',
    tabBarIcon: ShopIcon
  }}
  initialParams={{ section: undefined }}
/>

 

그리고 클릭해서 이동한 화면에서

useEffect 내에 isFocused 시 스크롤 처리를 해주면 된다.

 

여기서 useRef를 이용해서 현재 페이지의 전체 scrollView를 구독한 다음에

원하는 만큼 scrollRef.current.scrollTo로 내려줬다.

    // 화면 돌아왔을 때
    useEffect(() => {
        if (!!isFocused) {
            currentBottomTabRef.current = 'shop';
            if (firstTimeRef.current) {
                firstTimeRef.current = false;
                return;
            }

            profileRefetch();
            
            // Section이 Poke면
            if (route.params && route.params.section === 'Poke') {
                if (scrollRef.current) {
                    // RN의 scrollView는 기본적으로 scrollTo 메소드를 가지고 있다.
                    scrollRef.current.scrollTo({ y: 600, animated: true });
                }
                navigation.setParams({ section: undefined });
            }
        }
    }, [isFocused]);