로메오의 블로그

[React Native] Stack navigation 사용하기 (2022년 기준) 본문

Frontend/React

[React Native] Stack navigation 사용하기 (2022년 기준)

romeoh 2022. 10. 12. 11:51
반응형

React 목록

App.tsx

import React from 'react';
import {
  SafeAreaView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {Colors} from 'react-native/Libraries/NewAppScreen';

const App = () => {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <View>
        <Text>Restaurant App</Text>
        <View style={styles.content}>
          <Text>Explore</Text>
          <Text>Restaurant</Text>
          <Text>Profile</Text>
        </View>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  content: {
    justifyContent: 'center',
    alignItems: 'center',
    marginTop: 150,
  },
});

export default App;

 

 

 

 

파일 추가

$ mkdir screen
$ mkdir components
$ touch screen/Explore.tsx
$ touch screen/Restaurants.tsx
$ touch screen/Profile.tsx
$ touch components/RestaurantCard.tsx
$ touch components/Menu.tsx

 

 

RestaurantCard.tsx

import {View, Text, StyleSheet} from 'react-native';
import React from 'react';

interface Props {
  name: string;
}

const RestaurantCard: React.FC<Props> = ({name}) => {
  return (
    <View style={styles.container}>
      <Text>{name}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#efefef',
    padding: 16,
    marginTop: 8,
  },
});

export default RestaurantCard;

 

 

Menu.tsx

import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import React from 'react';

const Menu = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Navigation</Text>
      <TouchableOpacity
        onPress={() => {
          // Explore
        }}>
        <Text style={styles.link}>Explore</Text>
      </TouchableOpacity>
      <TouchableOpacity
        onPress={() => {
          // Restaurant
        }}>
        <Text style={styles.link}>Restaurant</Text>
      </TouchableOpacity>
      <TouchableOpacity
        onPress={() => {
          // Profile
        }}>
        <Text style={styles.link}>Profile</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#efefef',
    padding: 16,
    marginTop: 8,
  },
  title: {
    fontSize: 18,
  },
  link: {
    fontSize: 16,
    marginTop: 4,
    color: '#097ade',
    fontWeight: 'bold',
  },
});

export default Menu;

 

 

 

 

Explore.tsx

import {View, Text, StyleSheet} from 'react-native';
import React from 'react';
import RestaurantCard from '../components/RestaurantCard';

const ExploreScreen = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>식당 목록</Text>
      <View>
        <Text style={styles.sectionTitle}>근처식당</Text>
        <RestaurantCard name="일식" />
        <RestaurantCard name="중식" />
        <RestaurantCard name="한식" />

        <Text style={styles.sectionTitle}>인기식당</Text>
        <RestaurantCard name="양식" />
        <RestaurantCard name="분식" />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  restaurantCard: {
    backgroundColor: '#efefef',
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
  sectionTitle: {
    fontSize: 20,
    marginTop: 16,
  },
});

export default ExploreScreen;

 

Restaurants.tsx

import {View, Text, StyleSheet, ScrollView} from 'react-native';
import React from 'react';
import RestaurantCard from '../components/RestaurantCard';
import Menu from '../components/Menu';

const RestaurantsScreen = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>식당</Text>
      <ScrollView>
        <RestaurantCard name="일식" />
        <RestaurantCard name="중식" />
        <RestaurantCard name="한식" />
        <RestaurantCard name="양식" />
        <RestaurantCard name="분식" />
      </ScrollView>
      <Menu />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
});

export default RestaurantsScreen;

Profile.tsx

import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import React from 'react';

const ProfileScreen = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>Profile</Text>

      <Text>name: 홍길동</Text>
      <TouchableOpacity>
        <Text>편집</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
});

export default ProfileScreen;

 

 

 

 

 

 

 

 

react-native navigation 설치 

$ npm install @react-navigation/native --save
$ npm install react-native-screens react-native-safe-area-context --save
$ npm install @react-navigation/native-stack --save

 

 

 

iOS 모듈 설치

$ cd ios
$ pod install
$ cd ..

 

 

 

Android 모듈 설치

...
import android.os.Bundle;

public class MainActivity extends ReactActivity {

  ...

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
  }

  ...
}

 

 

 

App.tsx 수정

import React from 'react';
import ExploreScreen from './screen/Explore';
import ProfileScreen from './screen/Profile';
import RestaurantsScreen from './screen/Restaurants';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

const RootStack = createNativeStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <RootStack.Navigator initialRouteName="Explore">
        <RootStack.Screen name="Explore" component={ExploreScreen} />
        <RootStack.Screen name="Restaurants" component={RestaurantsScreen} />
        <RootStack.Screen name="Profile" component={ProfileScreen} />
      </RootStack.Navigator>
    </NavigationContainer>
  );
};

export default App;

 

 

 

 

Stack Navigation 

App.tsx

import React from 'react';
import ExploreScreen from './screen/Explore';
import ProfileScreen from './screen/Profile';
import RestaurantsScreen from './screen/Restaurants';
import RestaurantScreen from './screen/Restaurant';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

export type RootStackParams = {
  Explore: any;
  Restaurants: any;
  Profile: any;
  Restaurant: {
    name: string;
  };
};

const RootStack = createNativeStackNavigator<RootStackParams>();

const App = () => {
  return (
    <NavigationContainer>
      <RootStack.Navigator initialRouteName="Explore">
        <RootStack.Screen name="Explore" component={ExploreScreen} />
        <RootStack.Screen name="Restaurants" component={RestaurantsScreen} />
        <RootStack.Screen name="Profile" component={ProfileScreen} />
        <RootStack.Screen name="Restaurant" component={RestaurantScreen} />
      </RootStack.Navigator>
    </NavigationContainer>
  );
};

export default App;

 

 

Explore.tsx

import {View, Text, StyleSheet} from 'react-native';
import React from 'react';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
import RestaurantCard from '../components/RestaurantCard';
import Menu from '../components/Menu';
import {RootStackParams} from '../App';

type Props = NativeStackScreenProps<RootStackParams, 'Explore'>;

const ExploreScreen = ({navigation}: Props) => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>식당 목록</Text>
      <View>
        <Text style={styles.sectionTitle}>근처식당</Text>
        <RestaurantCard
          name="일식"
          onPress={() => {
            navigation.navigate('Explore');
          }}
        />
        <RestaurantCard
          name="중식"
          onPress={() => {
            navigation.navigate('Explore');
          }}
        />
        <RestaurantCard
          name="한식"
          onPress={() => {
            navigation.navigate('Explore');
          }}
        />

        <Text style={styles.sectionTitle}>인기식당</Text>
        <RestaurantCard
          name="양식"
          onPress={() => {
            navigation.navigate('Explore');
          }}
        />
        <RestaurantCard
          name="분식"
          onPress={() => {
            navigation.navigate('Explore');
          }}
        />
      </View>
      <Menu />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  restaurantCard: {
    backgroundColor: '#efefef',
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
  sectionTitle: {
    fontSize: 20,
    marginTop: 16,
  },
});

export default ExploreScreen;

 

 

 

Profile.tsx

import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import React from 'react';

const ProfileScreen = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>Profile</Text>

      <Text>name: 홍길동</Text>
      <TouchableOpacity>
        <Text>편집</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
});

export default ProfileScreen;

 

 

 

Restaurants.tsx

import {View, Text, StyleSheet, ScrollView} from 'react-native';
import React from 'react';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
import RestaurantCard from '../components/RestaurantCard';
import Menu from '../components/Menu';
import {RootStackParams} from '../App';

type Props = NativeStackScreenProps<RootStackParams, 'Restaurant'>;

const RestaurantsScreen = ({navigation}: Props) => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>식당</Text>
      <ScrollView>
        <RestaurantCard
          name="일식"
          onPress={name => {
            navigation.navigate('Restaurant', {name});
          }}
        />
        <RestaurantCard
          name="중식"
          onPress={name => {
            navigation.navigate('Restaurant', {name});
          }}
        />
        <RestaurantCard
          name="한식"
          onPress={name => {
            navigation.navigate('Restaurant', {name});
          }}
        />
        <RestaurantCard
          name="양식"
          onPress={name => {
            navigation.navigate('Restaurant', {name});
          }}
        />
        <RestaurantCard
          name="분식"
          onPress={name => {
            navigation.navigate('Restaurant', {name});
          }}
        />
      </ScrollView>
      <Menu />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
});

export default RestaurantsScreen;

 

 

 

Restaurant.tsx

import {View, Text, StyleSheet} from 'react-native';
import React from 'react';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
import RestaurantCard from '../components/RestaurantCard';
import {RootStackParams} from '../App';

type Props = NativeStackScreenProps<RootStackParams, 'Restaurant'>;

const RestaurantScreen = ({route, navigation}: Props) => {
  return (
    <View style={styles.container}>
      <Text style={styles.screenTitle}>{route.params.name}</Text>

      <Text>Relate Restaurant</Text>
      <RestaurantCard
        name="Sushi 1"
        onPress={() => {
          navigation.navigate('Restaurant', {name: 'Sushi 1'});
        }}
      />
      <RestaurantCard
        name="Sushi 2"
        onPress={() => {
          navigation.navigate('Restaurant', {name: 'Sushi 2'});
        }}
      />
      <RestaurantCard
        name="Sushi 3"
        onPress={() => {
          navigation.navigate('Restaurant', {name: 'Sushi 3'});
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    marginTop: 24,
  },
  screenTitle: {
    fontSize: 26,
    marginTop: 8,
    fontWeight: 'bold',
  },
});

export default RestaurantScreen;

 

 

 

RestaurantCard.tsx

import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import React from 'react';

interface Props {
  name: string;
  onPress: (name: string) => void;
}

const RestaurantCard: React.FC<Props> = ({name, onPress}) => {
  return (
    <TouchableOpacity onPress={() => onPress(name)}>
      <View style={styles.container}>
        <Text>{name}</Text>
      </View>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#efefef',
    padding: 16,
    marginTop: 8,
  },
});

export default RestaurantCard;

 

 

 

 

Menu.tsx

import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import React from 'react';
import {useNavigation} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {RootStackParams} from '../App';

const Menu = () => {
  const navigation =
    useNavigation<NativeStackNavigationProp<RootStackParams>>();

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Navigation</Text>
      <TouchableOpacity
        onPress={() => {
          navigation.navigate('Explore');
        }}>
        <Text style={styles.link}>Explore</Text>
      </TouchableOpacity>
      <TouchableOpacity
        onPress={() => {
          navigation.navigate('Restaurants');
        }}>
        <Text style={styles.link}>Restaurant</Text>
      </TouchableOpacity>
      <TouchableOpacity
        onPress={() => {
          navigation.navigate('Profile');
        }}>
        <Text style={styles.link}>Profile</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#efefef',
    padding: 16,
    marginTop: 8,
  },
  title: {
    fontSize: 18,
  },
  link: {
    fontSize: 16,
    marginTop: 4,
    color: '#097ade',
    fontWeight: 'bold',
  },
});

export default Menu;

 

 

 

 

 

React 목록

 

반응형
Comments