앱 개발 일지_navigate

윤승환·2022년 1월 30일
0

Sparta_APP

목록 보기
4/7

with Expo

앱 상태 바(Status Bar)관리

  • terminal

    expo install expo-status-bar

  • Js

    import {StatusBar} from 'expo-status-bar'
    <StatusBar style = "light"/>

네비게이터(navigator)

import React from 'react'
import MainPage from './pages/MainPage'
import DetailPage from './pages/DetailPage'

export default function App(){
  return(<MainPage/>)
  //return(<DetailPage/>)
  //return (<AboutPage/>)
}

-> 컴포넌트들 간의 이동을 자유롭게 해줄 수 있다.

import React from 'react';
//이제 모든 페이지 컴포넌트들이 끼워져있는 책갈피를 메인에 둘예정이므로
//컴포넌트를 더이상 불러오지 않아도 됩니다.
// import MainPage from './pages/MainPage';
// import DetailPage from './pages/DetailPage';
import { StatusBar } from 'expo-status-bar';

//메인에 세팅할 네비게이션 도구들을 가져옵니다.
import {NavigationContainer} from '@react-navigation/native';
import StackNavigator from './navigation/StackNavigator'

export default function App() {

  console.disableYellowBox = true;

  return ( 
  <NavigationContainer>
    <StatusBar style="black" />
    <StackNavigator/>
 </NavigationContainer>);
}

준비

  • 네비게이션 기본 설치 코드

    yarn add @react-navigation/native

  • 추가 설치 코드

    expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

스택네비게이션

  • Stack을 활용하여 뒤로가기를 사용할 수 있다.
  • 책갈피기능과 유사하다.
    1. 컴포넌트를 페이지화
    2. 내가 만든 컴포넌트를 Stack.Screen을 이용하여 페이지화
    3. 이렇게 만든 여러 페이지들을 책갈피 기능을 할 수 있도록, Stack.Navigator을 이용하여 스택네비게이터에 등록.
  • createStackNavigator 설치코드

    yarn add @react-navigation/stack

StackNavigator.js

https://reactnavigation.org/docs/stack-navigator/

  • Code
import React from 'react';
//설치한 스택 네비게이션 라이브러리를 가져옵니다
import { createStackNavigator } from '@react-navigation/stack';

//페이지로 만든 컴포넌트들을 불러옵니다
import DetailPage from '../pages/DetailPage';
import MainPage from '../pages/MainPage';

//스택 네비게이션 라이브러리가 제공해주는 여러 기능이 담겨있는 객체를 사용합니다
//그래서 이렇게 항상 상단에 선언하고 시작하는게 규칙입니다!
const Stack = createStackNavigator();


const StackNavigator = () =>{
    return (

        //컴포넌트들을 페이지처럼 여기게끔 해주는 기능을 하는 네비게이터 태그를 선언합니다.
        //위에서 선언한 const Stack = createStackNavigator(); Stack 변수에 들어있는 태그를 꺼내 사용합니다.
        //Stack.Navigator 태그 내부엔 페이지(화면)를 스타일링 할 수 있는 다양한 옵션들이 담겨 있습니다.
        <Stack.Navigator
            screenOptions={{
                headerStyle: {
                    backgroundColor: "black",
                    borderBottomColor: "black",
                    shadowColor: "black",
                    height:100
                },
                headerTintColor: "#FFFFFF",
                headerBackTitleVisible: false
            }}
            
        >

            {/* 컴포넌트를 페이지로 만들어주는 엘리먼트에 끼워 넣습니다. 이 자체로 이제 페이지 기능을 합니다*/}
            <Stack.Screen name="MainPage" component={MainPage}/>
            <Stack.Screen name="DetailPage" component={DetailPage}/>
        </Stack.Navigator>
    )
}

export default StackNavigator;
  • 사용 준비

    import React from 'react';
    //설치한 스택 네비게이션 라이브러리를 가져옵니다
    import { createStackNavigator } from '@react-navigation/stack';
    
    //페이지로 만든 컴포넌트들을 불러옵니다
    import DetailPage from '../pages/DetailPage';
    import MainPage from '../pages/MainPage';
    
    //스택 네비게이션 라이브러리가 제공해주는 여러 기능이 담겨있는 객체를 사용합니다
    //그래서 이렇게 항상 상단에 선언하고 시작하는게 규칙입니다!
    const Stack = createStackNavigator();
  • 기본 틀

    const StackNavigator = () =>{
        return (
                //페이지 기능이 들어가는 곳
        )
    }
    export default StackNavigator;
  • 스크린 옵션

            //위에서 선언한 const Stack = createStackNavigator(); Stack 변수에 들어있는 태그를 꺼내 사용합니다.
            //Stack.Navigator 태그 내부엔 페이지(화면)를 스타일링 할 수 있는 다양한 옵션들이 담겨 있습니다.
            <Stack.Navigator
                screenOptions={{
                    //공통적으로 적용될 헤더의 스타일
                    headerStyle: {
                        backgroundColor: "white",
                        borderBottomColor: "white",
                        shadowColor: "white",
                        height:100
                    },
                    //헤더의 텍스트를 왼쪾에 둘지 가운데에 둘지를 결정
                    headerTitleAlign:'left',
                    //헤더 text 색상
                    headerTintColor: "#000",
                    headerBackTitleVisible: false
                }}
    	>
                {/* 컴포넌트를 페이지로 만들어주는 엘리먼트에 끼워 넣습니다. 이 자체로 이제 페이지 기능을 합니다*/}
                <Stack.Screen name="MainPage" component={MainPage}/>
                <Stack.Screen name="DetailPage" component={DetailPage}/>
            </Stack.Navigator>
  • 페이지화

    <Stack.Screen name="MainPage" component={MainPage}/>
    <Stack.Screen name="DetailPage" component={DetailPage}/>

  • 책갈피화

    <Stack.Navigator> ~'페이지화 등록'~ </Stack.Navigator>

  • 사용하기
    NavigationContainer로 묶어서 '책'으로 반환한다.

APP.js

export default function App() {

  console.disableYellowBox = true;

  return ( 
  <NavigationContainer>
    <StatusBar style="black" />
    <StackNavigator/>
 </NavigationContainer>);
}

데이터와 함께 이동하기

navigation을 통해 page가 된 컴포넌트들은 두가지 속성을 지닌다.

export default function MainPage({navigation,route})

  • navigation 딕셔너리

제목변경

navigation.setOptions({
      title:'원하는 제목'
    }

이동하기
navigation.navigate("Stack.screen에서 name속성으로 정해준 이름")

  • route 딕셔너리

구조

//전달받은 데이터를 받는 route 딕셔너리
//비구조 할당 방식으로 route에 params 객체 키로 연결되어 전달되는 데이터를 꺼내 사용
//navigate 함수로 전달되는 딕셔너리 데이터는 다음과 같은 모습이기 때문입니다.

/*{
  route : {
    params :{
      title:title
    }
  }
}*/

const { title} = route.params;

전달하기

//name 속성을 전달해주고, 두 번째 인자로 딕셔너리 데이터를 전달해주면, Detail 페이지에서
//두번째 인자로 전달된 딕셔너리 데이터를 route 딕셔너리로 로 받을 수 있음
navigation.navigate("DetailPage",{
  title: title
})

ex)MainPage.js

useEffect(()=>{
//제목 변경
    navigation.setOptions({
      title:'나만의 꿀팁'
    })
		//뒤의 1000 숫자는 1초를 뜻함
    //1초 뒤에 실행되는 코드들이 담겨 있는 함수
    setTimeout(()=>{
        //헤더의 타이틀 변경 / 밖에 존재해도 상관없음
      //   navigation.setOptions({
      //     title:'나만의 꿀팁'
      // })  
        setState(data.tip)
        setCateState(data.tip)
        setReady(false)
    },1000)

페이지화 된 컴포넌트들은 페이지에 속한 컴포넌트에게 속성(함수)을 부여할 수 있다.

  • 페이지의 컴포넌트를 클릭하였을때, stackNavigate를 사용하려면 해당 컴포넌트를 굳이 페이지화하지 않아도 속성으로 부여받은 함수를 사용하면 된다.

ex)MainPage.js

cateState.map((content,i)=>{
            return (<Card content={content} key={i} navigation={navigation}/>)
          })

ex)Card.js

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

//MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
export default function Card({content,navigation}){
    return(
        //카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
        <TouchableOpacity style={styles.card} onPress={()=>{navigation.navigate('DetailPage',content)}}>
            <Image style={styles.cardImage} source={{uri:content.image}}/>
            <View style={styles.cardText}>
                <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
                <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
                <Text style={styles.cardDate}>{content.date}</Text>
            </View>
        </TouchableOpacity>
    )
}

ex)DetailPage.js

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert } from 'react-native';

export default function DetailPage({navigation,route}) {
		
		//초기 컴포넌트의 상태값을 설정 -> loading페이지를 활용해도 됨.
        //초기 값이 없으면 error -> 들어가자마자 데이터가 없으면 그릴 수 없으므로.
		//state, setState 뿐 아니라 이름을 마음대로 지정할 수 있음!
    const [tip, setTip] = useState({
        "idx":9,
        "category":"재테크",
        "title":"렌탈 서비스 금액 비교해보기",
        "image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
        "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
        "date":"2020.09.09"
    })
    
    useEffect(()=>{
        console.log(route)

	//Card.js에서 navigation.navigate 함수를 쓸때 두번째 인자로 content를 넘겨줬죠?
  //content는 딕셔너리 그 자체였으므로 route.params에 고대~로 남겨옵니다.
  //즉, route.params 는 content죠!

        navigation.setOptions({
						//setOptions로 페이지 타이틀도 지정 가능하고
            title:route.params.title,
						//StackNavigator에서 작성했던 옵션을 다시 수정할 수도 있습니다. 
            headerStyle: {
                backgroundColor: '#000',
                shadowColor: "#000",
            },
            headerTintColor: "#fff",
        })
        setTip(route.params)
    },[])

    const popup = () => {
        Alert.alert("팝업!!")
    }
    return ( 
        // ScrollView에서의 flex 숫자는 의미가 없습니다. 정확히 보여지는 화면을 몇등분 하지 않고
        // 화면에 넣은 컨텐츠를 모두 보여주려 스크롤 기능이 존재하기 때문입니다. 
        // 여기선 내부의 컨텐츠들 영역을 결정짓기 위해서 height 값과 margin,padding 값을 적절히 잘 이용해야 합니다. 
        <ScrollView style={styles.container}>
            <Image style={styles.image} source={{uri:tip.image}}/>
            <View style={styles.textContainer}>
                <Text style={styles.title}>{tip.title}</Text>
                <Text style={styles.desc}>{tip.desc}</Text>
                <TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
            </View>
            
        </ScrollView>
    
    )
}

공유하기

  • 공유하는 내용의 형식을 만들 수 있다.
const share = () => {
        Share.share({
            message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
        });
    }
    
<TouchableOpacity style={styles.button} onPress={()=>share()}><Text style={styles.buttonText}>팁 공유하기</Text></TouchableOpacity>

Linking

  • 설치(terminal)

    expo install expo-linking

const link = () => {
        Linking.openURL("https://https://velog.io/@yoon_s_whan")
    }
    
<TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>

0개의 댓글