[Sparta] 앱개발 3주차

HAM·2022년 12월 29일
1

[Sparta] 앱 개발

목록 보기
3/3
post-thumbnail

시작하자마자 냅다 코드 던저버리기

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

export default function DetailPage() {

    const tip = {
        "idx":9,
        "category":"재테크",
        "title":"렌탈 서비스 금액 비교해보기",
        "image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
        "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
        "date":"2020.09.09"
    }

    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 styles = StyleSheet.create({
    container:{
        backgroundColor:"#000"
    },
    image:{
        height:400,
        margin:10,
        marginTop:40,
        borderRadius:20
    },
    textContainer:{
        padding:20,
        justifyContent:'center',
        alignItems:'center'
    },
    title: {
        fontSize:20,
        fontWeight:'700',
        color:"#eee"
    },
    desc:{
        marginTop:10,
        color:"#eee"
    },
    button:{
        width:100,
        marginTop:20,
        padding:10,
        borderWidth:1,
        borderColor:'deeppink',
        borderRadius:7
    },
    buttonText:{
        color:'#fff',
        textAlign:'center'
    }
})

벨로그에서는 사진을 작게 보이게 할 순 없나 가독성이 넘 떨어지네

3주차 강의 시작하자마자 만들라고 해서 만들긴 했는데 보여주기 좋지 못해서 그냥 복붙한 거 올려요.. Sorry..

만들다보니 이제 페이지 하나 정도는 만들 수 있겠다 싶었어요..

페이지화에 대해 배우려고 여러 js파일을 만드는 과정임다


공부할 리액트 필수 지식

  • 컴포넌트(Component) : 정해진 엘리먼트들(요소)을 사용하여 만든 화면의 일부분
    UI의 요소, 요소를 재사용 가능한 부분으로 조각내서 운영하는 기법
  • 상태(State) : 컴포넌트에서 데이터를 유지하고 관리하기 위한 유일한 방법(그냥 사용할 데이터)
  • 속성(Props) : 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하는 방식(그냥 데이터 전달)
  • useEffect : 화면에 컴포넌트가 그려지면 처음 실행해야 하는 함수들을 모아두는 곳
컴포넌트 실습


카드 컴포넌트를 components 폴더에 만듬

카드 하나하나 만들었던 긴 코드를 주석으로 바꾸고 return에 Card 컴포넌트 하나만을 사용해서 카드를 보여주게 함 (변수 이름, 속성키 이름은 마음대로 해도 됨)

Card.js 확인! 카드 하나하나를 모듈화 (컴포넌트화) 해서 메인 코드 화면에 길었던 코드들이 간결해졌고 코드들은 Card.js에 들어가 있음

상태 실습

  • 코드가 준비가 되었든 되지 않았든 바로 처음 실행시키고 싶은 코드는 useEffect에 넣음
  • const [state,setState] = useState([])
    useState에서는 실제 컴포넌트에서 사용할 데이터state와 그 데이터를 변경하거나 수정할 때 쓰는 setState 두 가지를 전달해줌
  • useEffect(()=>{setState(data)},[]) 이 뒤에 있는 setState를 통해서 data.json에 있는 데이터를 준비시키고 있는 것을 알 수 있음

? 에러가 생기는 이유는 ?

  • const [state,setState] = useState([])
    useState는 초기값을 전달해주는 함수 (빈 리스트)
    초기값은 state에 담기게 됨 (컴포넌트 안에서 사용할 상태변수)
    state에 담긴 데이터를 수정하려면 항상 setState 함수를 이용해서 변경해야됨
    > useEffect(()=>{setState(data)},[])
     setState 안에 data를 전달하는 것을 볼 수 있음
     -> state 안에 data가 담기게 됨
  • 화면이 그려질 때 바로 tip에다가 state.tip 을 실행하려고 하고 있음
    하지만 위의 코드처럼 tip이라는 딕셔너리가 없음 (state의 상태변수가 빈 리스트, 키 없음)
    -> 오류 발생
    -> 이럴 때는 화면이 그려질 때 먼저 로딩 화면을 보여주고 데이터가 준비된 다음에 실제 데이터가 준비가 되면 그 화면을 보여주는 기법이 필요함

! 해결 !

  • Loading.js 를 만들어 코드가 준비될 때까지 보여주게 함
  • MainPage.js
    import Loading from '../components/Loading';하고
    return ready ? <Loading/> : 를 통해 로딩 화면이 한 번 그려지게 되고 useEffect가 실행이 됨
    > useEffect(()=>{
    	setTimeout(()=>{
        	setState(data)
        	setReady(false)
    	},1000)
      },[])
      data를 담고 로딩화면을 걷어내기 위해 ready의 값을 true에서 false로 변경하여 data의 화면을 보여주게 함
      

너무 너무 너무 어려운 부분인 것 같다.. 강의 5번은 넘게 돌려본듯 ㅜ


카테고리 기능 넣기

  • 코드를 살펴보면 기존 const 말고 새로운 const를 만듬
  • 기존 const는 전체 데이터를 보관할 때만 사용
  • Card.js에 카드들이 카테고리별로 구분되어 있는데 카테고리를 눌렀을 때 그 카테고리별로만 볼 수 있게 하는 것
	const [ready,setReady] = useState(true) 
    	useEffect(()=>{
    		setTimeout(()=>{			
        		//메인 페이지 컴포넌트에서 항상 가지고 있을 꿀팁 전체 데이터
                setState(data.tip)
                //카테고리 버튼을 누르는 거 마다 달라질 상태변수
        		setCateState(data.tip)
                //로딩화면 걷어내는 것
        		setReady(false)
    		},1000)
  		},[])


기존 코드는 비슷하고 onPress에 어떤 함수가 바인딩 되어 있는 지가 중요함
-> category 함수가 실행 되게끔 바인딩 되어 있음


category함수 확인
-> cate라는 변수를 넘겨받고 있음
-> .fliter함수를 사용
('생활'카테고리를 눌렀을 때 category함수가 실행됨
-> cate=='생활'이 되고 '전체보기'가 아니기 때문에 else문이 실행되게 됨
-> 요소 하나하나 돌릴 때마다 카테고리의 값이 '생활'이면 그 해당하는 값으로 리스트를 새로 만들어짐
-> CateState에 저장됨)


state였던 부분이 CateState라고 변경 되어 있음 (이제 화면에서 보이게 될 상태 변수는 CateState를 사용하기 때문)


앱 상태 바(Status Bar) 관리

  • Expo SDK (Expo에서 제공해주는 앱 기능 도구들을 확인 가능)
    https://docs.expo.dev/versions/latest/
  • Expo 상태 바 설치
    expo install expo-status-bar

    터미널 창을 분할로 해서 두 개 열어두고 하면 좋답니당
    오류가 생기면 터미널 하나로만 해야 됩니당
  • StatusBar import 하기 (import하는 방식은 조금씩 다르니까 공식문서 확인)

네비게이터

: 리액트 네이티브에서 페이지 간의 이동, 페이지에서 이동할 때 데이터를 가지고 가는 방식

  • react-navigation 공식 문서
    https://reactnavigation.org/

  • 네비게이션 설치 코드
    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.Screen
      책갈피 Stack.Navigator

    • creatStackNavigator 설치 코드
      yarn add @react-navigation/stack

    • navigation 폴더를 만들고 StackNavigator.js 파일을 만듬

    • 사용할 코드 분석
      1. 사용 준비

      import React from 'react';
      //설치한 스택 네비게이션 라이브러리를 가져옵니다
      import { createStackNavigator } from '@react-navigation/stack';
      
      //페이지로 만든 컴포넌트들을 불러옵니다
      import DetailPage from '../pages/DetailPage';
      import MainPage from '../pages/MainPage';
      
      //스택 네비게이션 라이브러리가 제공해주는 여러 기능이 담겨있는 객체를 사용합니다
      //그래서 이렇게 항상 상단에 선언하고 시작하는게 규칙입니다!
      const Stack = createStackNavigator();
      1. 기본 툴
        //리액트의 모~든 파일은 컴포넌트라 생각하고
         //페이지 기능을 해주는 모든 기능이 담겨 있는 컴포넌트를 만든다 생각하세요!
        const StackNavigator = () =>{
          return (
                      /// 페이지 기능이 들어갈 곳
          )
        }
        export default StackNavigator;
      2. 스크린 옵션
        //컴포넌트들을 페이지처럼 여기게끔 해주는 기능을 하는 네비게이터 태그를 선언합니다.
         	//위에서 선언한 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>
      3. 페이지 연결
        {/* 컴포넌트를 페이지로 만들어주는 엘리먼트에 끼워 넣습니다. 이 자체로 이제 페이지 기능을 합니다*/}
        <Stack.Screen name="MainPage" component={MainPage}/>
        <Stack.Screen name="DetailPage" component={DetailPage}/>
    • StackNavigator에 코드 넣기

    • App.js 코드 확인하고 실행화면

      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>);
      }

      항상 return 으로 한 페이지만 바꿔서 볼 수 있었는데 return에 다양한 코드들이 들어가 있음

    • 컨텐츠 윗 부분에 MainPage라는 이름이 띄워져 있음

      MainPage가 써져 있는 코드를 확인해볼 수 있음

    • screenOptions를 사용해서 공통적인 정보를 보여주게 설정할 수 있음

    • 메인 페이지에서 특정한 카드 버튼을 누르면 다른 페이지로 넘어가게 됨

      • 페이지를 이동시키려면, 책갈피가 페이지들에게 부여해준 페이지 이동 기능을 사용해야함

      • Stack.screen에 등록된 모든 페이지 컴포넌트들은 navigationroute 라는 딕셔너리(객체)를 속성으로 넘겨받아 사용할 수 있음

        		//navigation 객체가 가지고 있는 두 함수(setOptions와 navigate)
        
        			//해당 페이지의 제목을 설정할 수 있음
        			navigation.setOptions({
        				title:'나만의 꿀팁'
               })
        
               //Stack.screen에서 name 속성으로 정해준 이름을 지정해주면 해당 페이지로 이동하는 함수
               navigation.navigate("DetailPage")
        
               //name 속성을 전달해주고, 두 번째 인자로 딕셔너리 데이터를 전달해주면, Detail 페이지에서 
               //두번째 인자로 전달된 딕셔너리 데이터를 route 딕셔너리로 로 받을 수 있음
               navigation.navigate("DetailPage",{
                 title: title
               })
               
               //전달받은 데이터를 받는 route 딕셔너리
               //비구조 할당 방식으로 route에 params 객체 키로 연결되어 전달되는 데이터를 꺼내 사용
               //navigate 함수로 전달되는 딕셔너리 데이터는 다음과 같은 모습이기 때문입니다.
               /*
               {
               	route : {
                 	params :{
                     	itle:title
                         }
                     }
                 }
                 */
                 const { title} = route.params;

        어떻게 사용하는 지 알 수 있는 코드 전혀 모르겠음

      • 실습해보기
        MainPage.js에서 바뀐 코드
        export default function MainPAge({navigation,route})를 보면 navigation딕셔너리랑 route딕셔너리를 비구조 할당 방식으로 바로 받아서 사용할 준비를 함

        Stack.Screen에서 component={MainPage} 메인 페이지를 컴포넌트와 연결해 페이지화 당하면 두 가지 딕셔너리를 쓸 수 있는 데(페이지화된 애들한테만 쓸 수 있음) 그게 위의 navigationroute이고 이 메인 페이지에 두 가지 딕셔너리를 넘겨주고 있다는 것을 알 수 있음

      • 카드들도 똑같이 네이게이션을 붙여주면 됨
        navigationroute 두 가지 딕셔너리는 페이지화된 애들한테만 쓸 수 있는데 네비게이션 도구를 자식 컴포넌트에 넘겨줘서 자식 컴포넌트에도 사용할 수 있음

      • 데이터를 가지고 페이지 이동하기

            		navigation.navigate("Detail",{
            			title: title
            })


        Card.js코드를 확인하면 카드를 누르면 그 상세 페이지가 컨텐츠와 함께 넘어가게끔 코드를 구현했고

        DetailPage.js 또한 페이지화 되어 있으니 navigation, route를 사용했음

        이 코드에서 useEffect에서 디테일 페이지로 들어갈 때마다 위의 제목을 원래 카드 제목으로 띄울 수 있게 변경하기 위해 setOptions를 사용함 (route.params.에는 Card.js로부터 넘겨받은 데이터가 들어 있기 때문에 사용함)


Share 공유기능 (페이지 내용 공유하기)

  • 설치 할 라이브러리 X, react-native에서 기본적으로 제공하는 공유 기능 사용
    import {Share} from "react-native";
  • 좀 느리지만 '팁 공유하기' 버튼을 누르면 공유할 수 있게 뜨는 모습을 확인할 수 있음

    Share.share 함수에 공유하고 싶은 내용을 딕셔너리 형태의 메세지 키에 물려주면 외부에 해당 내용을 공유할 수 있음

Linking 외부 링크 클릭

  • DetailPage.js에 있는 글의 출처를 바로가기 버튼을 사용해 만들 예정
  • expo install expo-linking 터미널에서 설치 후
    DetailPage,js에서 import * as Linking from 'expo-linking';을 해줌
  • 새로 생긴 '외부 링크' 버튼을 누르면 외부 사이트로 이동하는 모습을 볼 수 있음
    (Linking을 사용하여 전화 버튼을 누르면 바로 통화할 수 있게 만들어주는 환경도 만들 수 있음)

숙제

  1. 어바웃 화면 페이지화 시키고 버튼 추가하기

    22.12.30
    MainPage.js

    • 오늘의 날씨 바로 밑에 TouchableOpacity를 사용해서 버튼을 만들고 박스 스타일은 middleButtonAll을 사용하여 기본의 버튼과 동일하게 만드려다가 크기가 약간 달라 topButton을 통해 만들었음 (그 안에 텍스트는 기존과 동일해서 middleButtonTextAll을 사용해서 만듬)
    • '소개 페이지' 버튼을 눌렀을 때 소개 페이지로 넘어가야 하기 때문에 onPressnavigation.navigate('AboutPage')를 해뒀음 (이 부분을 어떻게 해야할지 고민하다가 힌트 좀 봤음ㅠㅠ)
    StackNavigator.js

    • import AboutPage from '../pages/AboutPage';를 해주고 다른 부분은 잘 몰라서 일단 <Stack.Screen name="AboutPage" component={AboutPage}/>을 똑같이 적어두었더니 어설프지만 '메인 페이지'에서 '소개 페이지' 버튼을 눌렀을 때 'AboutPage'가 바로 나옴
    AboutPage.js

    • import {useEffect} from 'react' 를 하고 상단의 '소개 페이지'가 적힌 부분을 수정할 수 있게 useEffect를 씀
    • 숙제에 올린 사진에는 '소개 페이지' 스타일이 조금 다른 것 같길래 구글링을 해서 headerTitleStyle을 만들었음
    • 힌트에 <StatusBar style="light" /> 이게 있었는데 본 코드와 큰 차이가 없는 거 같아 일단 적지 않았음, 그래서 위에 import { StatusBar } from 'expo-status-bar'; 부분이 흐림으로 표시됨
    • 추가로 기존에 있던 '여러분의 인스타계정' 버튼을 누르면 인스타 계정으로 들어갈 수 있도록 import * as Linking from 'expo-linking';를 하고 link 함수를 만들어 인스타 계정 주소를 적고 기존의 코드에 onPress={()=>link()}를 추가함
  2. 꿀팁 찜 페이지가 화면을 만들기
    이상하네 아무리 해도 안돼

어머 보기만 해도 어렵네? 어쩌겠어 해내야지
차차 해서 올려야지..

profile
Frontend developer

0개의 댓글