티스토리 뷰

공부/리액트 네이티브

4주

데자와 맛있다 2021. 7. 1. 20:22

4-1---------------------------------------------------------------------------------------

서버리스: 서버를 직접 구축하지 않고 서버를 사용하는 방법

파이어베이스: 서버리스의 일종

4-2---------------------------------------------------------------------------------------

-서버 이용 두가지 방법

1. 서버가 제공하는 도메인 사용

2. 서버가 만들어 놓은 함수를 사용

=>둘다 서버로 부터 응답 받기위해 어떤 규칙에 따라 요청을 해야됨

 

-서버에서는 대부분 json데이터 형식으로 데이터를 준다

-파이어 베이스에 요청하여 데이터를 받아오자

-필요한 데이터를 불러오는것은 useEffect함수 내부에서 한다(화면이 켜지자 마자 보여야되니까)

4-3---------------------------------------------------------------------------------------

-도메인으로 날씨 서버 외부 api를 가져와 보자

-날씨정보를 알기 위해서는 거기 위치를 알아야됨 위치는 expo에서 또 제공하는 함수가 있다

=> expo install expo-location

import { StatusBar } from 'expo-status-bar';//expo-status-bar에 저장된 이름 그대로 StatusBar라는 이름으로 도구 사용
import * as Location from "expo-location";//내가 직접 도구의 이름을 Location으로 지정하여 사용
MainPage.js
mport React,{useState,useEffect} from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
import { StatusBar } from 'expo-status-bar';
import * as Location from "expo-location";  //Location import

export default function MainPage({navigation,route}) {
  console.disableYellowBox = true;
  //return 구문 밖에서는 슬래시 두개 방식으로 주석

  //기존 꿀팁을 저장하고 있을 상태
  const [state,setState] = useState([])
  //카테고리에 따라 다른 꿀팁을 그때그때 저장관리할 상태
  const [cateState,setCateState] = useState([])

  //컴포넌트에 상태를 여러개 만들어도 됨
  //관리할 상태이름과 함수는 자유자재로 정의할 수 있음
  //초기 상태값으로 리스트, 참거짓형, 딕셔너리, 숫자, 문자 등등 다양하게 들어갈 수 있음.
  const [ready,setReady] = useState(true)

  useEffect(()=>{
     
    //뒤의 1000 숫자는 1초를 뜻함
    //1초 뒤에 실행되는 코드들이 담겨 있는 함수
    setTimeout(()=>{
        //헤더의 타이틀 변경
        navigation.setOptions({
            title:'나만의 꿀팁'
        })
        //꿀팁 데이터로 모두 초기화 준비
        let tip = data.tip;
        setState(tip)
        setCateState(tip)
        getLocation()//위치 불러오는 함수
        setReady(false)
    },1000)

    
  },[])

  const getLocation = async () => {
    //수많은 로직중에 에러가 발생하면
    //해당 에러를 포착하여 로직을 멈추고,에러를 해결하기 위한 catch 영역 로직이 실행
    try {
      //자바스크립트 함수의 실행순서를 고정하기 위해 쓰는 async,await
      await Location.requestPermissionsAsync();//사용자에게 위치 권한 얻는 팝업창
      //사용자가 허용하지 않으면 하단의 두 줄은 실행되지 않고 종료
      const locationData= await Location.getCurrentPositionAsync();//현재 위치 좌표를 가져오는 함수
       //위치 정보를 return하여 locationData에 삽입
      console.log(locationData)

    } catch (error) {
      //혹시나 위치를 못가져올 경우를 대비해서, 안내를 준비합니다
      Alert.alert("위치를 찾을 수가 없습니다.", "앱을 껏다 켜볼까요?");
    }
  }

    const category = (cate) => {
        if(cate == "전체보기"){
            //전체보기면 원래 꿀팁 데이터를 담고 있는 상태값으로 다시 초기화
            setCateState(state)
        }else{
            setCateState(state.filter((d)=>{
                return d.category == cate
            }))
        }
    }


  let todayWeather = 10 + 17;
    let todayCondition = "흐림"

  //처음 ready 상태값은 true 이므로 ? 물음표 바로 뒤에 값이 반환(그려짐)됨
  //useEffect로 인해 데이터가 준비되고, ready 값이 변경되면 : 콜론 뒤의 값이 반환(그려짐)
  return ready ? <Loading/> :  (
    /*
      return 구문 안에서는 {슬래시 + * 방식으로 주석
    */
    <ScrollView style={styles.container}>
        <StatusBar style="black" />
        {/* <Text style={styles.title}>나만의 꿀팁</Text> */}
        <Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
        <TouchableOpacity style={styles.aboutButton} onPress={()=>{navigation.navigate('AboutPage')}}>
          <Text style={styles.aboutButtonText}>소개 페이지</Text>
        </TouchableOpacity>
        <Image style={styles.mainImage} source={main}/>
        <ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}>
            <TouchableOpacity style={styles.middleButtonAll} onPress={()=>{category('전체보기')}}><Text style={styles.middleButtonTextAll}>전체보기</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>
    </ScrollView>
  );
}
.
.
.
(생략)

-자바 스크립트는 코드가 위에서 아래로 한줄한줄 실행되는것이 아니라 먼저 실행되는것이 먼저 끝남(?) 따라서 코드가 반드시 순차적으로 실행되어야 하는 경우엔 함수에 async와 await를 사용한다

함수 앞에 async붙이고 내부 함수에 await를 붙임

4-4---------------------------------------------------------------------------------------

-날씨 서버 외부 api를 사용해 보자

https://openweathermap.org/api

 

Weather API - OpenWeatherMap

Please, sign up to use our fast and easy-to-work weather APIs for free. In case your requirements go beyond our freemium account conditions, you may check the entire list of our subscription plans. You can read the How to Start guide and enjoy using our po

openweathermap.org

-key값으로 날씨 정보를 불러와야 한다, key는 OpenWeatherMap에서 제공한다. 가입을 해야 줌

-도메인 형식으로 주소를 써서 정보를 얻기 위해서는 axios라는 도구가 필요하다 이는 자바 스크립트의 도구이다.

yarn add axios <-명령어로 axios설치

import axios from "axios"
.
.
.
const getLocation = async () => {
    //수많은 로직중에 에러가 발생하면
    //해당 에러를 포착하여 로직을 멈추고,에러를 해결하기 위한 catch 영역 로직이 실행
    try {
      //자바스크립트 함수의 실행순서를 고정하기 위해 쓰는 async,await
      await Location.requestPermissionsAsync();
      const locationData= await Location.getCurrentPositionAsync();
      const latitude = locationData['coords']['latitude']
      const longitude = locationData['coords']['longitude']
      const API_KEY = "cfc258c75e1da2149c33daffd07a911d";
      const result = await axios.get(
        `http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`
      );


      console.log(result)


    } catch (error) {
      //혹시나 위치를 못가져올 경우를 대비해서, 안내를 준비합니다
      Alert.alert("위치를 찾을 수가 없습니다.", "앱을 껏다 켜볼까요?");
    }
  }
.
.
.
(생략)

위 처럼 위도와 경도를 받아서 key와 함께 주소 형식으로get함수에 넣어주면 서버에서 어떤 데이터를 반환해줌

https://openweathermap.org/stations

 

Weather Stations - OpenWeatherMap

We are glad to announce our new API version for managing your personal weather stations - Weather Stations API 3.0 (beta). It went through some essential changes in comparison with the previous version. The main improvement is that users now have more flex

openweathermap.org

반환 받는 데이터 형식은 위 링크 참조

const [weather, setWeather] = useState({
    temp : 0,
    condition : ''
  })//변경내용 반영을 위한 상태관리
.
.

const getLocation = async () => {

    //수많은 로직중에 에러가 발생하면
    //해당 에러를 포착하여 로직을 멈추고,에러를 해결하기 위한 catch 영역 로직이 실행
    try {
      //자바스크립트 함수의 실행순서를 고정하기 위해 쓰는 async,await
      await Location.requestPermissionsAsync();
      const locationData= await Location.getCurrentPositionAsync();
      const latitude = locationData['coords']['latitude']
      const longitude = locationData['coords']['longitude']
      const API_KEY = "cfc258c75e1da2149c33daffd07a911d";
      const result = await axios.get(
        `http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`
      );

      const temp = result.data.main.temp; //result에서 받은 json데이터에서 temp만 뽑아옴
      const condition = result.data.weather[0].main
      
      console.log(temp)
      console.log(condition)

      //오랜만에 복습해보는 객체 리터럴 방식으로 딕셔너리 구성하기!!
      //잘 기억이 안난다면 1주차 강의 6-5를 다시 복습해보세요!
      setWeather({
        temp,condition
      })


    } catch (error) {
      //혹시나 위치를 못가져올 경우를 대비해서, 안내를 준비합니다
      Alert.alert("위치를 찾을 수가 없습니다.", "앱을 껏다 켜볼까요?");
    }
  }

4-5---------------------------------------------------------------------------------------

-서버리스?

서버리스는 서버를 만들지 않고 데이터를 저장, 수정, 삭제 하는 서버의 기능을 간단히 사용할수있도록 하는 서비스

서버를 직접 구축할 필요없이 기능을 사용할수있게 하는것

 

-파이어 베이스도 서버리스의 한 종류이다.

 

-어떤 기능이 필요할지 먼저 생각하자

1. tip들을 서버에서 가져와서 화면에 띄우자!-> 앱의 용량이 더 적어질것이다.

2. 사용자들이 팁을 찜하면 어떤 사용자가 어떤 팁을 저장하였는지 서버에 저장한다

3. 사용자가 저장한 팁을 또 서버에서 불러와야 된다

 

4-6---------------------------------------------------------------------------------------

-파이어 베이스?

구글에서 만든 서버리스 서비스이다. 서버를 직접 만들지 않아도 간단히 서버의 기능을 사용하도록 한다

파이어 베이스에서는 실시간 데이터베이스, 인증, 클라우드 스토리지, 호스팅, 성능 모니터링 등등의 기능을 지원함

파이어 베이스 서비스를 사용하려면 일단 파이어 베이스에 가입하고 프로젝트를 생성한 다음에 사용할 서비스를 활성화 해야 된다

https://firebase.google.com/?hl=ko 

 

Firebase

Firebase는 고품질 앱을 빠르게 개발하고 비즈니스를 성장시키는 데 도움이 되는 Google의 모바일 플랫폼입니다.

firebase.google.com

위 링크에서 파이어 베이스 프로젝트 가입, 생성이 가능하다. 

1. 구글 로그인: 파이어 베이스는 구글의 서비스이므로 구글 계정이 있다면 가입된것이다.

2. 위 링크로 들어가 프로젝트를 만든다

로그인
프로젝트 생성
프로젝트 이름 정하기

애널리틱스 설정도 됨 이건 뭐냐면 앱을 내가 파이어 베이스 이용해서 만들고 배포하면 어느 지역의 사용자가 뭘 했고 트래픽이 얼마고 이런식의 정보를 제공해줌

위와 같이 애널리틱스 위치를 대한민국으로 하면 대한민국 시간대로 맞춰서 정보를 전달해줌

설정이 다 끝났으면 하단의 프로젝트 만들기 버튼을 누른다

기다려 주면 프로젝트가 만들어졌다고 함 

4-7---------------------------------------------------------------------------------------

-프로젝트를 만들었으므로 app에 이 파이어베이스 프로젝트를 사용한다고 주소를 알려줘야됨

우선 아까 프로젝트를 다 만들고 나서 확인 버튼을 누르면 위와 같은 화면이 뜨는데 저기서 4개의 버튼중 하나를 선택해야된다

지금 내가 하고있는것은 리액트 네이티브이므로 자바 스크립트를 사용하고 있다

따라서 웹 버튼을 클릭한다

클릭하면 위와 같은 화면이 나옴 빈칸에 내 앱의 닉네임을 적자

호스팅을 하지 않을것이므로 아래의 체크는 하지 않는다

그후 앱 등록 버튼을 클릭하면 app에 어떤식으로 이 파이어베이스 주소를 알려줘야되는지 자바스크립트 코드가 출력된다

다 봤으면 화면 맨 아래의 콘솔로 이동 버튼을 클릭한다

 

나중에 또 위의 자바 스크립트 코드를 보고싶으면 좌측 톱니바퀴에서 프로젝트 설정으로 들어가면 나옴

 

이제 app에 파이어베이스를 설정하자

이를 위해서 expo에서 제공하는 파이어베이스 도구를 설치한다

https://docs.expo.io/guides/using-firebase/

 

Using Firebase - Expo Documentation

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.io

expo install firebase 입력

 

그 다음 아까 프로젝트 설정에서 봤던 코드를 js형태로 넣어야됨

firebaseConfig.js를 App.js와 같은 디렉터리에 생성한다

firebaseConfig.js
//import * as firebase from 'firebase/app';
import firebase from 'firebase/app';

// 사용할 파이어베이스 서비스 주석을 해제합니다
//import "firebase/auth";
import "firebase/database";
//import "firebase/firestore";
//import "firebase/functions";
import "firebase/storage";

// Initialize Firebase
//파이어베이스 사이트에서 봤던 연결정보를 여기에 가져옵니다
const firebaseConfig = {
    //이곳에 프로젝트 설정에서 봤던 var firebaseConfig={}에서 {}안의 내용들을 넣음
};

//사용 방법입니다. 
//파이어베이스 연결에 혹시 오류가 있을 경우를 대비한 코드로 알아두면 됩니다.
if (!firebase.apps.length) {
    firebase.initializeApp(firebaseConfig);
}

export const firebase_db = firebase.database()

위와 같이 바꾼다.

4-8---------------------------------------------------------------------------------------

-파이어베이스의 파일 스토리지 기능을 써보자

어떤 이미지를 저장할때 서버에 저장하고 불러오기 하는것

파이어베이스에 어떤 이미지를 저장하면 그 이미지가 저장된 곳의 주소를 반환해준다

시작하기 버튼을 클릭하면 보안 규칙 설명 창이 뜨는데 다음을 누름

그러면 그 다음에는 

이런게 나옴 저건 뭐냐면 내가 이미지 저장할 서버가 어느 위치에 있는 서버로 할지 정하는것

아무거나 고르면됨 그래도 되도록이면 가까운게 빠르게 불러올테니 아시아쪽 서버를 고르자

완료 버튼을 누르면 된다

스토리지가 다 만들어지면 위와 같은 화면이 나온다

폴더를 만들어 관리하고 파일을 업로드 할수있다.

파일을 업로드하면 해당 파일을 접근할수있는 주소가 나온다.

4-9---------------------------------------------------------------------------------------

-파이어 베이스에 리얼타임 데이터베이스로 json데이터를 저장하자

-sql은 엑셀 형태, 리얼타임 데이터베이스는 json형태로 데이터를 저장

아까처럼 데이터 베이스 서버를 어느 위치로 할지 정한다

일단 잠금모드로 시작한다

사용 설정 버튼을 클릭하면 리얼타임 데이터 베이스가 생긴다

완료되면 위와 같은 화면이 나온다

앞은 key이고 뒤에 null은 val이다 null에 내가 넣고싶은 json데이터를 넣으면 된다

아까 잠금모드로 규칙을 정했다 우리는 app에서 원격으로 json에 접근해야 되므로 아까 규칙을 바꿔야된다

app에서 읽고 써야되므로 둘다 true로 값을 바꾸고 게시를 클릭한다

이제 json데이터를 넣기 위해 데이터를 클릭

위의 점 3개를 클릭해서 json파일을 내 컴퓨터에서 불러온다

여기다 업로드 하고 수정도 가능함

이 json데이터에 접근하려면 주소 형태로 접근하면 된다

위 그림의 tip val에 접근하려면 http주소/tip 이런식으로 접근

4-10---------------------------------------------------------------------------------------

-useEffect안에 파이어베이스에서 값을 가져오는 함수를 만들어야 된다

-데이터를 가져오기 위해서는 databaseURL이 필요, 이 값은 아까 firebaseConfig.js에 넣었던

firevaseConfig에 들어가게 된다. 근데 맨 첨에 리얼타임 데이터 베이스를 안하고 firebaseConfig를 보면 databaseURL은 없다. 따라서 리얼타임 데이터 베이스를 만들고 난 다음에 다시 firebaseConfig를 넣어줘야 된다

-파이어 베이스 설명서를 보기 위해서는 내 프로젝트로 들어간 다음 메인화면에서 문서로 이동 버튼을 클릭한다

https://firebase.google.com/docs?authuser=0 

 

문서  |  Firebase

firebase.google.com

웹 시작하기의 API참조를 클릭

문서>firebase.database>Database를 보니

위와 같이 firebase.database().ref("원하는위치") 하면 데이터 베이스에서 그 값을 가져온다

https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html

 

Keeping our Promises (and Callbacks)

The official blog for Firebase, Google's mobile development platform

firebase.googleblog.com

firebase_db.ref('/tip').once('value').then((snapshot) => { let tip = snapshot.val(); })

이래하면 데이터 베이스의tip에서 딕셔너리를 뽑아서 tip에 넣게됨

 

firebaseConfig.js
//import * as firebase from 'firebase/app';
import firebase from 'firebase/app';

// 사용할 파이어베이스 서비스 주석을 해제합니다
//import "firebase/auth";
import "firebase/database";
//import "firebase/firestore";
//import "firebase/functions";
import "firebase/storage";

// Initialize Firebase
//파이어베이스 사이트에서 봤던 연결정보를 여기에 가져옵니다
const firebaseConfig = {
   //생략
};

//사용 방법입니다. 
//파이어베이스 연결에 혹시 오류가 있을 경우를 대비한 코드로 알아두면 됩니다.
if (!firebase.apps.length) {
    firebase.initializeApp(firebaseConfig);
}

export const firebase_db = firebase.database()//export 해야 다른js에서 접근가능
MainPage.js
.
.
.
import {firebase_db} from "../firebaseConfig"//위에서 export하였기때문에 import가능

.
.
.

useEffect(()=>{
     
    //뒤의 1000 숫자는 1초를 뜻함
    //1초 뒤에 실행되는 코드들이 담겨 있는 함수
    setTimeout(()=>{
        //헤더의 타이틀 변경
        navigation.setOptions({
            title:'나만의 꿀팁'
        })
        firebase_db.ref('/tip').once('value').then((snapshot) => {
          console.log("파이어베이스에서 데이터 가져왔습니다!!")
          let tip = snapshot.val();
          setState(tip)
          setCateState(tip)
          getLocation()
          setReady(false)
        });
        // setTimeout(()=>{
        //     let tip = data.tip;
        //     setState(tip)
        //     setCateState(tip)
        //     getLocation()
        //     setReady(false)
        // },500)
    },1000)


    
  },[])

4-11---------------------------------------------------------------------------------------

-현재 Card.js상태는 데이터가 있는 딕셔너리 전체를 전달하는 형식

-> 앱 퍼포먼스에 영향을 줌

-> 각 데이터는 고유한 인덱스 번호를 가지며 이 번호를 이용하여 필요한 값만 가져오자

 

Card.js를 아래와 같이 수정

idx:content.idx   => content의 idx를 idx라는 이름으로 전달한다

 

DetailPage.js를 아래와 같이 수정

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

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

    const [tip, setTip] = useState({
        "idx":9,
        "category":"재테크",
        "title":"렌탈 서비스 금액 비교해보기",
        "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Frental.png?alt=media&token=97a55844-f077-4aeb-8402-e0a27221570b",
        "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
        "date":"2020.09.09"
    })
    
    useEffect(()=>{
        console.log(route)
        navigation.setOptions({
            title:route.params.title,
            headerStyle: {
                backgroundColor: '#000',
                shadowColor: "#000",
            },
            headerTintColor: "#fff",
        })
        //넘어온 데이터는 route.params에 들어 있습니다.
        const { idx } = route.params;//인덱스 번호를 받아옴
        firebase_db.ref('/tip/'+idx).once('value').then((snapshot) => {//인덱스 번호를 주소로 해서 그 값을 얻어옴
            let tip = snapshot.val();
            setTip(tip)
        });
    },[])

    const popup = () => {
        Alert.alert("팝업!!")
    }

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

    const link = () => {
        Linking.openURL("https://spartacodingclub.kr")
    }
    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>
                <View style={styles.buttonGroup}>
                    <TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
                    <TouchableOpacity style={styles.button} onPress={()=>share()}><Text style={styles.buttonText}>팁 공유하기</Text></TouchableOpacity>
                    <TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>
                </View>
                
            </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"
    },
    buttonGroup: {
        flexDirection:"row",
    },
    button:{
        width:90,
        marginTop:20,
        marginRight:10,
        marginLeft:10,
        padding:10,
        borderWidth:1,
        borderColor:'deeppink',
        borderRadius:7
    },
    buttonText:{
        color:'#fff',
        textAlign:'center'
    }
})

4-12---------------------------------------------------------------------------------------

-파이어베이스 데이터 베이스에 값을 저장하기

-각 사용자들은 자신이 원하는 팁을 찜할수있고 이 찜한 내용이 데이터베이스로 들어간다

-그렇다면 각 사용자는 구분되어야 한다

-각 사용자 구분을 위한 도구를 expo에서 제공한다

expo install expo-constants 로 다운받자

아래와 같이 DetailPage.js를 수정

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert,Share } from 'react-native';
import * as Linking from 'expo-linking';
import {firebase_db} from "../firebaseConfig"//파이어 베이스 사용 위해 import
import Constants from 'expo-constants';//constants를 이용해 각 사용자 구분

export default function DetailPage({navigation,route}) {
    let user_idx = Constants.installationId
    console.log(user_idx)
    const [tip, setTip] = useState({
        "idx":9,
        "category":"재테크",
        "title":"렌탈 서비스 금액 비교해보기",
        "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Frental.png?alt=media&token=97a55844-f077-4aeb-8402-e0a27221570b",
        "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
        "date":"2020.09.09"
    })
    
    useEffect(()=>{
        console.log(route)
        navigation.setOptions({
            title:route.params.title,
            headerStyle: {
                backgroundColor: '#000',
                shadowColor: "#000",
            },
            headerTintColor: "#fff",
        })
        //넘어온 데이터는 route.params에 들어 있습니다.
        const { idx } = route.params;
        firebase_db.ref('/tip/'+idx).once('value').then((snapshot) => {
            let tip = snapshot.val();
            setTip(tip)
        });
    },[])

    const like = () => {
        
        // like 방 안에
        // 특정 사용자 방안에
        // 특정 찜 데이터 아이디 방안에
        // 특정 찜 데이터 몽땅 저장!
        // 찜 데이터 방 > 사용자 방 > 어떤 찜인지 아이디
        const user_id = Constants.installationId;
        firebase_db.ref('/like/'+user_idx+'/'+ tip.idx).set(tip,function(error){
            console.log(error)
            Alert.alert("찜 완료!")
        });
    }

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

    const link = () => {
        Linking.openURL("https://spartacodingclub.kr")
    }
    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>
                <View style={styles.buttonGroup}>
                    <TouchableOpacity style={styles.button} onPress={()=>like()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
                    <TouchableOpacity style={styles.button} onPress={()=>share()}><Text style={styles.buttonText}>팁 공유하기</Text></TouchableOpacity>
                    <TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>
                </View>
                
            </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"
    },
    buttonGroup: {
        flexDirection:"row",
    },
    button:{
        width:90,
        marginTop:20,
        marginRight:10,
        marginLeft:10,
        padding:10,
        borderWidth:1,
        borderColor:'deeppink',
        borderRadius:7
    },
    buttonText:{
        color:'#fff',
        textAlign:'center'
    }
})

그러면 아래와 같이 데이터 베이스에 사용자가 찜한 데이터가 저장된다

 

'공부 > 리액트 네이티브' 카테고리의 다른 글

5주  (0) 2021.07.07
1주  (0) 2021.06.23
3주  (0) 2021.06.23
2주  (0) 2021.06.21
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함