본문 바로가기
DEV/App 개발

React Native 앱 만들기 :: React Native, Expo 앱 화면 만들기(2)

by 올커 2022. 7. 28.

 

리액트 네이티브(React Native),

엑스포(Expo)를 활용한 앱 만들기


들어가면서..

앱 기초지식인 컴포넌트, 속성(Props), 상태(useState)와 useEffect을 이해한다.

 VSCode, React, React-native와 Expo를 활용하여

'나만의 꿀팁'이라는 컨셉의 앱 페이지를 제작하고, 페이지 이동을 위한 스택 네비게이션을 활용해본다.

 

1. 리액트 기본 개념 (컴포넌트, 상태, 속성, Hook)

 본 앱을 제작하면서 리액트 네이티브(React-native)를 사용하지만, 이는 곧 리액트(React.js) 기반으로

만들어진 앱 개발 기술이기 때문에 아래 개념들을 잘 이해해야 페이지를 구성할 수 있다.

  - 컴포넌트(Component) : UI를 구성하는 요소, 함수형, 클래스형이 있다.

    ex) 상위) App  →  하위), SafeAreaView, View, Text, ...

    앱 개발시 컴포넌트화는 기능별 구성요소화를 통해 재사용이 용이해진다.

  - 상태(State, useState) : 

    (1) state : 컴포넌트의 (상태값을) 변경 가능한 데이터 저장소. 출력을 위해서 render 필요.

                    뷰의 렌더링이 갱신될 때 동적 정보를 출력하기 위해 사용

                    setState(메서드)를 통해 상태값 변경

    (2) useState : 컴포넌트의 상태값을 관리하는 함수

      * 리액트에서 use로 시작하는 다양한 함수가 내장되어 있는데 이들을 Hook이라고 부른다.

         Hook은 상태 관리, 최적화, 컴포넌트 작동 흐름 관리 등의 기능을 수행가능하다.

const App = () => {
	const [A, setA] = useState(true);
    return(
    	<SafeAreaView>
        	<Box rounded={true} size="large" color="red" />
        </SafeAreaView>
    );
};

export default App;

   위 식은 useState의 활용 예시이다.

   여기서 A는 상태값, setA는 상태값을 변경(업데이트)하는 함수이다.

   SetA를 호출하면, A값이 true로 변경되며, useState 함수에 넣어준 파라미터는 상태값의 초깃값이다.

  - 속성(Props, properties) : 상위 컴포넌트로부터 전달받는 속성(데이터)을 지닌 객체

                                            ex) numberOfLines, resizeMode, ...

 아래 코드를 보면 content라는 이름으로 MainPage.js에서 Card.js로 속성(데이터)를 전달하고 있는 모습이다.

MainPage.js

   - 컴포넌트에 속성(데이터)을 부여하여 전달할 땐, 키와 벨류(content={content})형태로 전달할 것
   - 컴포넌트를 반복문 돌릴 땐, 컴포넌트마다 고유하다는 것을 표현하기 위해, map에서 나오는 인덱스(i)를
      key={i} 속성 전달형태로 꼭 넣을 것

Card.js

비구조 할당 방식(딕셔너리에서 키값을 바로 취해서 변수로 함수내에서 즉시 사용하는 방식)
MainPage.js에서 넘겨준 속성은 실제 받게되는 컴포넌트엥서 딕셔너리 데이터를 받았다고 생각하면 쉽다.

  - useEffect : 화면이 그려진 다음 가장 먼저 실행되는 함수, 주로 데이터를 준비할 때 사용

  화면 생성 → useEffect가 데이터 준비 → 상태 데이터 업데이트 후 화면 재생성

useEffect(()=>{
	...화면이 그려진 다음 가장 먼저 실행되야 할 코드 작성 공간
},[])

※ 로딩 화면

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

export default function Loading(){
    return(<View style={styles.container}><Text style={styles.title}>준비중입니다...</Text></View>)
}


const styles = StyleSheet.create({
    container: {
        //앱의 배경 색
        flex:1,
        justifyContent:'center',
        alignItems:'center',
        backgroundColor: '#fdc453',
    },
    title: {
        fontSize:20,
        fontWeight:'700'
    }

})

※ MainPage.js 컴포넌트

    useEffect(()=>{
      navigation.setOptions({
        title:'My Tips'
      })
      setTimeout(()=>{
          setState(data.tip)
          setCateState(data.tip)
          setReady(false)
      },1000)
    }, [])

※ 적용 모습

2. 앱 상태 바(Status Bar) 사용

// 사전 설치
expo install expo-status-bar

 - Status Bar는 컴포넌트마다 다르게 적용할 수도 있고, 앱 전체에 공통적으로 적용할 수도 있다.

  특히 Style을 "auto", "light", "black"에 따라 색상이 다르니 배경색에 맞게 지정하도록 유의해야 한다.

import { StatusBar } from 'expo-status-bar';

export default function MainPage({navigation, route}) {
	...
    <StatusBar style='auto' />
    ...
}

3. 스택 네비게이션(Stack Navigation)

 - 앱의 기능들을 페이지화 시켜주고, 페이지간 이동을 가능하게 해주는 라이브러리

// 사전 설치
yarn add @react-navigation/native
expo install react-native-screens react-native-safe-area-context react-native-gesture-handler
yarn add @react-navigation/stack

 - Stack.Screen(페이지), Stack.Navigator(책갈피)

  - ../navigation/StackNavigator.js 코드 내용

import React from 'react';
//스택 네비게이션 라이브러리 호출
import { createStackNavigator } from '@react-navigation/stack';

//페이지로 만들 컴포넌트 불러오기
import DetailPage from '../pages/DetailPage';
import MainPage from '../pages/MainPage';
import AboutPage from '../pages/AboutPage';
import LikePage from '../pages/LikePage';

//항상 상단에 선언하고 시작하는 것이 규칙!
const Stack = createStackNavigator();
const StackNavigator = () =>{         // 컴포넌트를 페이지처럼 여기게하는 기능인 네비게이터 태그 선언
    return (
        //위에서 선언한 const Stack = createStackNavigator(); Stack 변수에 들어있는 태그를 꺼내 사용합니다.
        //Stack.Navigator 태그 내부(화면)를 스타일링하는 옵션↓
        <Stack.Navigator
            screenOptions={{
                headerStyle: {
                    backgroundColor: "black",
                    borderBottomColor: "black",
                    shadowColor: "black",
                    height:100
                },
                headerTitleAlign:'left',
                headerTintColor: "#fff",
                headerBackTitleVisible: false
            }}
        >

            {/*  컴포넌트를 페이지로 만들어주는 엘리먼트에 할당  */}
            <Stack.Screen name="MainPage" component={MainPage}/>
            <Stack.Screen name="DetailPage" component={DetailPage}/>
            <Stack.Screen name="AboutPage" component={AboutPage}/>
            <Stack.Screen name="LikePage" component={LikePage}/>
        </Stack.Navigator>
    )
}

export default StackNavigator;

 - Navigation을 적용한 App.js 코드 내용

import React from 'react';
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="light" />
    <StackNavigator/>
  </NavigationContainer>);
}

 - MainPage.js 적용 모습

export default function MainPage({navigation, route}) {
    
    const [state,setState] = useState([])
    const [cateState,setCateState] = useState([])
    const [ready,setReady] = useState(true)

    useEffect(()=>{
      navigation.setOptions({
        title:'My Tips'
      })
      setTimeout(()=>{
          setState(data.tip)
          setCateState(data.tip)
          setReady(false)
      },1000)
    }, [])

    const category = (cate) => {
      if(cate=="전체보기"){
          setCateState(state)
      }else{
          setCateState(state.filter((d)=>{
              return d.category == cate
          }))
      }
    }



  return ready ? <Loading/> : (
    <SafeAreaView style={styles.SafeArea}>
      <ScrollView style={styles.container}>   
      
		...
        
        <ScrollView style={styles.middleContainer} horizontal indicatorStyle='white'>
            <TouchableOpacity style={styles.middleButtonAll} onPress={()=>{category('전체보기')}}><Text style={styles.middleButtonText}>전체보기</Text></TouchableOpacity>
            <TouchableOpacity style={styles.middleButton01} onPress={()=>{category('생활')}}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity>
            <TouchableOpacity style={styles.middleButton02} onPress={()=>{category('재테크')}}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity>
            <TouchableOpacity style={styles.middleButton03} onPress={()=>{category('반려견')}}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity>
            <TouchableOpacity style={styles.middleButton04} onPress={()=>{navigation.navigate('LikePage')}}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity>
        </ScrollView>

        <View style={styles.cardContainer}>
          {/*하나의 카드 영역을 나타내는 View */}
          {
            cateState.map((content,i)=>{
                return (<Card content={content} key={i} navigation={navigation}/>)
            })
          }
        </View>

        <StatusBar style='auto' />
      </ScrollView>      
    </SafeAreaView>
  );
}

4. 외부 공유하기(Share)

- Share를 통해 페이지를 외부로 공유할 수 있다.

import { Share } from "react-native";

...

export default function DetailPage({navigation,route}) {
...

const share = () => {
	Share.share({
    	message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
    });
}

5. Link 이동하기

 - 사전 설치

expo install expo-linking

 - 사용하기

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert,Share } from 'react-native';
import * as Linking from 'expo-linking';

export default function DetailPage({navigation,route}) {
...

	const link = () => {
        Linking.openURL("https://ggommappooh.tistory.com/")   //이동시킬 url 삽입
    }

6. 생각하기

 - 이번 개발일지를 작성하면서 짧은 기간 내에 정말 많은 개념들을 활용해서 개발했던 것 같다.

   기초 이론이 되는 React, 그리고 React-native의 각 컴포넌트, 속성, 상태에 대한 개념을 계속해서 개발하면서 상기하고

   별도의 도서 등을 통해 계속 익혀나가야 할 것 같다.

반응형

댓글