TIL 블로그

React-Navigation 적응기 2 본문

Final Project

React-Navigation 적응기 2

bsnow 2019. 12. 3. 20:12

react-navigation 적응기 1

https://soyoonty.tistory.com/140

 

React-Navigation 적응기 1

React를 이용하여 웹 페이지를 만들 때는 react-router 를 사용하면 되지만, React-Native 로 모바일 어플을 만들 때는 화면전환을 위해 navigation 을 사용해야 한다. 네비게이션 선택지는 react-navigation reac..

soyoonty.tistory.com


진행 중인 프로젝트에서 만든 어플의 navigation 전체 구조는 아래와 같다. 

 

 


본격적으로 코드를 작성한다. 

내가 코드를 작성할 때는 저 모든 네비게이션을 다 사용한 예시를 찾기가 어려워서 

삽질을 많이 했다.

 

1. Stack Navigator 생성 

연관된 스크린들끼리 stack 으로 묶는다.

createStackNavigator를 이용했다. 

 

const habitStack = createStackNavigator(
  {
    Habits : { screen : Habits },
    AddHabit : { screen : AddHabit },
    ModifyHabit : { screen : ModifyHabit },
  },
  {
    headerMode: 'none' });

const todosStack = createStackNavigator(
  {
    Todos : { screen : Todos },
    AddTodos : { screen : AddTodos },
    ModifyTodos : { screen : ModifyTodos },
  },
  {
    headerMode: 'none' });

const rewardStack = createStackNavigator(
  {
    Reward : { screen : Rewards },
    AddReward : { screen : AddReward },
    ModifyReward : { screen : ModifyReward },
  },
  {
    headerMode: 'none' });

 

2. Tab Navigator 생성 (하단바)

createMaterialTopTabNavigator 를 이용했다. 

 

위에서 생성한 Stack 을 여기에 넣는다. 

 

const AppTabNavigator = createMaterialTopTabNavigator(
  {
    habits : { screen : habitStack },
    todos : { screen : todosStack },
    rewards : { screen : rewardStack },
  },
  // 뒷 부분은 옵션. 
  {
    animationEnabled: true,
    swipeEnabled: true, // 탭을 누르지 않고 swipe 로 이동이 가능하게. 
    tabBarPosition: 'bottom', // "top" 하면 상단바
    tabBarOptions: {
      style: {
        ...Platform.select({
          android:{ // 안드로이드 어플일 때 
            backgroundColor:'#110133',
            height : '7%',
          },
        }),
      },
      labelStyle: {
        fontSize: 15,
      },
      activeTintColor: '#ffdc34', // 현재 focus된 탭의 색깔
      inactiveTintColor: 'white', // 현재 unfocus 된 탭의 색깔 
      upperCaseLabel: false,
    },
    // 스크린 이름말고 아이콘도 따로 넣을 수 있다.
  });

 

3. Drawer Navigator 생성 (사이드바)

createDrawerNavigator 를 이용했다. 

 

위에서 생성한 Tab 을 여기에 넣는다. 

 

 

const DrawerStack = createDrawerNavigator(
  {
    AppTabNavigator : { screen : AppTabNavigator },
    Itemshop : { screen : Itemshop },
    Item : { screen : Item },
  },
  {
    contentComponent: DrawerContainer,
    initialRouteName : 'AppTabNavigator',
    // 위의 stack navigator 에서는 헤더를 사용하지 않고, 여기서는 사용했다. 
    navigationOptions : ({ navigation }) => ({
      headerTitleStyle: { alignSelf: 'center', color : 'white', fontSize : 20 },
      title : 'JUST DO THE NEXT RIGHT THING',
      headerLeft:
      <View style = {styles.menu}>
        <Ionicons name = 'md-menu' onPress={() => navigation.toggleDrawer()} size = {34} color = '#ffdc34' />
        </View>,
      headerStyle: {
        backgroundColor: '#110133',
      },
    }),
  });

drawer를 열고 닫기 위해 아래의 helper들을 사용할 수 있다.

this.props.navigation.openDrawer(); 
this.props.navigation.closeDrawer();
this.props.navigation.toggleDrawer();

 

4. Switch Navigator 생성

위에서 생성한 Drawer 를 여기에 넣는다. 

 

5. createAppContainer 로 감싼다. 

 

const drawerNavigator = createStackNavigator({
  DrawerStack: { screen: DrawerStack },      
})

const HomeScreen = createAppContainer(createSwitchNavigator(
  {
    AuthLoading: AuthLoadingScreen,
    Signin : Signin,
    Signup : Signup,
    drawerNavigator : { screen : drawerNavigator },
  },
  {
    initialRouteName: 'AuthLoading',
  },
));

 

 

 


가장 고민했던 부분은

B screen에서 변경된 내용이 A screen에 돌아왔을 때 반영이 되었으면 좋겠는데, 안 된다! 재랜더가 안 돼!

이 부분이었다. 

 

이미 마운트가 된 상태였기 때문에, unmount 되지 않는 이상 다시 componentdidmount에서 뭔가를 불러와서 변경시키는 것은 불가능했고. 

그래서 어쩔 수 없이 store를 이용해서 복잡하게 구현을 했는데, 

 

navigation에는 이런 유용한 addlistender 가 있었다..

mount 상태와 상관없이 그 스크린에 focus가 맞춰질 때, 그리고 focus 가 나갈 때 

어떤 함수를 실행할 수 있게 해 준다. 

 

addListener - Subscribe to updates to navigation lifecycle

React Navigation emits events to screen components that subscribe to them:

  • willFocus - the screen will focus
  • didFocus - the screen focused (if there was a transition, the transition completed)
  • willBlur - the screen will be unfocused
  • didBlur - the screen unfocused (if there was a transition, the transition completed)
  public async componentDidMount() {
    const { navigation } = this.props;
    // 이 스크린에 focus 가 맞춰지면 무조건 안의 함수가 실행됨
    navigation.addListener('didFocus', () => {
      let count = 0;
      for(let i=0; i<this.props.todosarr.length; i++){
        if (this.props.todosarr[i]["completed"]) {
          count++
        }
      }
      this.setState({
        completecount : count,
      });
    });
    }

 

그래서 앞에 쓴 코드들은 좀 복잡하게 구현했지만, 

마지막에 고민하던 문제는 위의 이벤트들을 이용해서 편하게 구현할 수 있었다. 

 

여기까지 react-navigation과 친해진 과정 .. 

 

 

 


참고 링크

https://medium.com/async-la/react-navigation-stacks-tabs-and-drawers-oh-my-92edd606e4db

 

React Navigation: Stacks, Tabs, and Drawers … Oh my!

This is Part III of a series on React Navigation. If you’ve never used this library before, check out my other posts: Up and Running and…

medium.com

https://medium.com/@flyingSquirrel/react-native-addlistner를-활용한-login-status-에-따른-rendering-410f080be23

 

[React Native] addListner를 활용한 login status 에 따른 rendering

React Native를 할 때 가장 어려웠던 점을 꼽으라면, this.props.navigation.navigate(‘이동하고자하는 Component이름’)을 Handling하는 것이었어요 :(

medium.com