파이어 베이스의 기능

하이루·2021년 10월 29일
0

1) 파일 저장소 (파일 스토리지 --> 이미지 파일)

--> 멀리 있는 파일 저장소에 이미지, 사용할 파일 등등을 넣어놓고 필요할 때마다 꺼내쓰는 용도로 사용

구글 클라우드와 유사하지만 다른 점은

 구글 클라우드의 경우 파일에 접근하기 위해 일일이 구글 클라우드에 접속해야 함

파이어베이스가 제공하는 파일 저장소의 경우 파일 하나하나에 주소를 제공하여 주소를 입력하는 것 만으로 그 파일에 접근할 수 있다.

서비스 사용방법

--> 파이어베이스에 접속 --> 내가 만든 서버에 접속 --> 서버의 서비스들 중 Storage를 선택 및 활성화(좌측 메뉴바에 있음)

이미지 파일의 경우

--> 파일 저장소 스토리지
--> Storage에 넣는 것 만으로 파이어베이스가 해당 이미지에 고유 주소를 부여해주기 때문에 쉽게 외부에서 접근할 수 있다.

리얼타임 데이터베이스 (--> JSON형태 택스트 파일)

--> JSON형태로 저장/관리되는 데이터베이스 서비스

--> 데이터베이스 주소는 파이어베이스를 앱에 연결할 때 주어지는 (SDK) JSON데이터에 제공되어있음 --> 따로 기입하지 않아도 됨

--> 데이터 사용에 대한 공식문서 : https://firebase.google.com/docs/reference/js/v8/firebase.database.Reference?authuser=2#once

서비스 사용방법

--> 파이어 베이스가 제공하는 서비스 중 Realtime Database 클릭

--> 규칙 탭을 통해 제 3자가 데이터베이스의 데이터에 접근, 수정, 삭제 할 수 있는지 설정할 수 있음

공식문서 : https://firebase.google.com/docs/database/web/read-and-write?hl=ko

[데이터 조회]

ex) firebaseConfig.js --> 파이어베이스 SDK를 expo도구를 사용하여 압축하여 export

  //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 = {
  apiKey: "AIzaSyBKG2xY91x23W8PF1231k5OUJ5o9kHSKYQeNWUw",
  authDomain: "sparta-psytest-gun.firebaseapp.com",
  databaseURL: "https://sparta-psytest-gun.firebaseio.com",
  projectId: "sparta-psytest-gun",
  storageBucket: "sparta-psytest-gun.appspot.com",
  messagingSenderId: "781790378482",
  appId: "1:78179037128482:web:ddbca5330779f67b947136b",
  measurementId: "G-3F5L9F3340Q3"
  };

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

  export const firebase_db = firebase.database()
  

import {firebase_db} from "../firebaseConfig"
위 코드의 export된 부분을 가져오고 있음

firebaseConfig는 파이어베이스 SDK 코드를 담고 있는 파일

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

--> 위의 코드의 방식으로 데이터 조회
--> 위 코드의 의미는 해당 파이어베이스 서버(SDK에 기입된)의 리얼타임 DB에 tip에 해당하는 이름(즉 리얼타임 DB에서 /tip이라는 주소에 존재하는)의 JSON데이터를 가져와서 tip이라는 변수에 할당한 것이다

--> firebase_db.ref('/tip').once('value').then((snapshot)

ref('/tip') --> 이부분에서 데이터베이스의 어느 JSON데이터에 접근할지 설정 (여기서는 tip이라는 이름의 JSON에 접근)

--> 리얼타임 DB의 모든 주소를 적지 않아도 되는 이유는 파이어베이스 연결시의 SDK에 주소가 이미 기입되어 있기 떄문


[사용 방법]

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

-->서버리스를 이용하여 데이터베이스를 조회하기 위해 파이어베이스 측에서 정해놓은 API 사용방법
-->조회한 데이터는 snapshot 부분에 담겨서 {} 내부에서 사용할 수 있는데, 그 중 실제 우리에게 필요한 데이터는 snapshot.val()로 가져와 변수에 담아 사용할 수 있음

snapshot.val()

--> 위의 함수 내에서 이 함수를 사용하여 데이터를 조회해 가져올 수 있음

ex) 예제

      ......
      import {firebase_db} from "../firebaseConfig"
      ......
      
      ......
       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)
},[])
......

특정 데이터만 가져오기

{
    "tip":[
        {
            "idx":0,
            "category":"생활",
            "title":"먹다 남은 피자를 촉촉하게!",
            "image":"https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpizza.png?alt=media&token=1a099927-d818-45d4-b48a-7906fd0d2ad3",
            "desc":"먹다 남은 피자는 수분이 날라가기 때문에 처음처럼 맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아 전자레인지 안에서 1분 30초에서 2분 정도 함께 돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지 안에서 수증기를 일으키고, 피자에 촉촉함을 더해줍니다.",
            "date":"2020.09.09"
        },
        {
            "idx":1,
            "category":"생활",
            "title":"바나나를 싱싱하게 보관하기",
            "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fbanana.png?alt=media&token=886aeb87-7ff8-4498-8674-7e4f878b8845",
            "desc":"바나나에 날파리가 꼬이거나 금방 익어버리는 것을 예방하기 위한 방법인데요. 바나나 양쪽 끝을 자른 후, 보관용 케이스나 비닐봉지에 묶어 밀봉합니다. 그리고 냉장고에 넣어주면 되는데요. 하루에 1~2개씩 꺼내서 싱싱하게 먹을 수 있습니다.",
            "date":"2020.09.09"
        },
        {
            "idx":2,
            "category":"생활",
            "title":"셔츠에 묻은 볼펜 자국 없애기",
            

각각의 Json 데이터는 idx같은 키를 통해 고유번호로 넘버링 하는 것이 원칙이다.

--> 이 idx를 통해 딕셔너리를 식별하여 특정 데이터만 가져오는 것이다.

idx를 이용하여 특정 딕셔너리의 데이터를 가져오기

Card.js

       ......
        export default function Card({content,navigation}){
        return(
            //카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
            
            <TouchableOpacity style={styles.card} onPress={()=>{navigation.navigate('DetailPage',{idx:content.idx})}}>

                <Image style={styles.cardImage} source={{uri:content.image}}/>
                <View style={styles.cardText}>
       ......

DetailPage.js

            ......
               //넘어온 데이터는 route.params에 들어 있습니다.
            const { idx } = route.params;
            firebase_db.ref('/tip/'+idx).once('value').then((snapshot) => {
                let tip = snapshot.val();
                setTip(tip)
            });
        },[])
            ......

1) Card.js 에서 버튼을 클릭하면 DatailPage로 이동하면서, 해당 버튼을 이루는 딕셔너리의 idx넘버를 같이 전달한다.
2) DetailPage에서 idx넘버를 바탕으로 서버에 해당 딕셔너리 데이터를 요청하여 그 데이터로 DatailPage를 채운다.

DetailPage 코드의
firebase_db.ref('/tip/'+idx) 부분을 보면
파이어베이스 서버의 tip이라는 딕셔너리의 해당 idx넘버를 가진 딕셔너리를 선별한다는 것을 볼 수 있다.

[파이어 베이스의 리얼타임DB 저장 예시]



--> 이처럼 idx번호와 리얼타임DB에 저장되는 딕셔너리의 주소 번호가 일치하기 때문에 위의 방식처럼 처리가 가능했던 것
위의 데이터들은
sparta-myhoneytip-hyeon-default-rtdb/tip/0,
sparta-myhoneytip-hyeon-default-rtdb/tip/1,
sparta-myhoneytip-hyeon-default-rtdb/tip/2
의 저장주소를 가짐

          but DB주소인 sparta-myhoneytip-hyeon-default-rtdb부분은 
          이미 firebaseConfig.js에 딕셔너리 형태로 저장되어 있기 떄문에 굳이 써주지 않는다(상단의 코드 참고)
          
         -->firebaseConfig.js를 담는 변수 firebase_db가 SDK(파이어베이스의 정보가 담긴 딕셔너리)를 
         압축하고 있음(expo도구를 사용하여)  (상단 코드 참고)
         
          --> 즉, 마스터키에 이미 정보가 있으니까 일일이 써줄 필요가 없는것
          
          

리얼타임 데이터베이스 쓰기

   firebase_db.ref('/like/'+user_idx+'/'+ tip.idx).set(tip,function(error){
              console.log(error)
              Alert.alert("찜 완료!")
          });
          
          

--> ref의 매개변수로 데이터를 입력할 주소를 넣음 --> DB에 미리 만들어 놓지 않더라도 저장하는 과정에서 만듬

set함수에 저장할 데이터를 매개변수로 넣음,
이후 function함수는 에러가 발생할 경우 에러코드 받는 함수인 듯 함

고유한 기계번호로 userID만들기

expo가 제공하는 expo-constants 도구

expo install expo-constants

--> 도구 받는 코드

도구 불러오기 (import)

	import Constants from 'expo-constants';
    

해당 스마트폰을 고유한 번호로 가져오기

 let user_idx = Constants.installationId
 
 --> 위 코드는 이 코드를 실행한 스마트폰에 대해 고유한 식별번호를 리턴한다.
       --> 즉, 이것 자체로 유니크한 ID로 사용할 수 있다. 
       --> 이는 스마트폰을 기반으로 정보를 저장할 경우(따로 로그인이 필요 없는 경우), 
       이 데이터를 DB에 정리하여 저장하는 것을 용이하게 한다.
       
           --> 하지만 스마트폰에 대한 고유번호이므로 유저에 대해 데이터를 다르게 할 경우
           (즉 다른 기기로도 해당 유저의 정보에 접속하는 등의 작업이 필요하다면)
               따로 userData를 수집하는 것이 맞다.
            --> 즉 이런 경우는 로그인 기능을 구현하는 것이 맞다.
            
           

LikePage.js --> 데이터를 불러올 때 Object를 못읽는 문제 해결

    import React,{useState,useEffect} from "react";
    import {View, Image,Text,StyleSheet,ScrollView} from "react-native";
    import { TouchableOpacity } from "react-native-gesture-handler";
    import Loading from "../components/Loading";
    import LikeCard from "../components/LikeCard";
    import  Constants from "expo-constants";
    import { firebase_db } from "../firebaseConfig";

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


        const [tip, setTip] = useState([])

    const [ready,setReady] = useState(true)

    useEffect(()=>{
        navigation.setOptions({

            title:"꿀팁 찜"
        })


        const userIdx = Constants.installationId
        firebase_db.ref('/like/'+userIdx).once('value').then((snapshot)=>{
            let tip = snapshot.val();
            console.log(tip)

            let tip_list = Object.values(tip)

            if(tip_list.length > 0){
                setTip(tip_list)
                setReady(false)
            }
            //  if(tip.length > 0){
            //     setTip(tip);
            //     setReady(false)
            //  }
        })
    },[])


    const reload = () =>{
        const user_id = Constants.installationId;
        firebase_db.ref('/like/'+user_id).once('value').then((snapshot) => {
                        //snapshot에 값이 있는지 없는지 체크하는 exists 함수 사용
            if(snapshot.exists()){
                let tip = snapshot.val();
                let tip_list = Object.values(tip)
                setTip(tip_list)
            }else{
                setReady(true)
                setTip([])
            }

        })
    }


        return ready ? <Loading/> : (
            <ScrollView style={styles.container}>
               <View style={styles.cardContainer}>
                    {
                    tip.map((content,i)=>{
                        return (<LikeCard content={content} key={i} reload={reload} navigation={navigation}/>)
                    })
                    }
                </View>
            </ScrollView>
        )
    }

    const styles = StyleSheet.create({
        container:{
            backgroundColor:"#fff"
        },
        cardContainer:{
            marginTop:20
        }
    })
    
    

가져온 data의 object를 불어서 문제 해결한 부분

  firebase_db.ref('/like/'+userIdx).once('value').then((snapshot)=>{
          let tip = snapshot.val();
          console.log(tip)

          let tip_list = Object.values(tip)

          if(tip_list.length > 0){
              setTip(tip_list)
              setReady(false)
          }
          //  if(tip.length > 0){
          //     setTip(tip);
          //     setReady(false)
          //  }
      })

reload 함수를 만든 후 LikeCard에 매개변수로 넘기는 것으로 LikeCard.js컴포넌트에서 LikePage.js에 영향을 미칠 수 있게 하였다.

(즉 A컴포넌트(LikeCard)가 A컴포넌트를 일부로써 사용하는 B컴포넌트(LikePage)의 다른 부분에 영향을 미칠 수 있게 함 )

reload 부분

const reload = () =>{
const user_id = Constants.installationId;
firebase_db.ref('/like/'+user_id).once('value').then((snapshot) => {
//snapshot에 값이 있는지 없는지 체크하는 exists 함수 사용
if(snapshot.exists()){
let tip = snapshot.val();
let tip_list = Object.values(tip)
setTip(tip_list)
}else{
setReady(true)
setTip([])
}

                })
            }

reload함수를 LikeCard의 매개변수(속성, props)에 넣어 전달한 부분

   <View style={styles.cardContainer}>
                          {
                          tip.map((content,i)=>{
                              return (<LikeCard content={content} key={i} reload={reload} navigation={navigation}/>)
                          })
                          }
                      </View>

그렇게 전달받은 reload함수를 LikeCard컴포넌트가 사용하여 LikePage에 영향을 끼치는 부분 --> 아래 부분의 코드

  export default function LikeCard({content,reload,navigation}){

    const remove = (idx)=>{
    const user_id = Constants.installationId;
    firebase_db.ref('/like/'+user_id+'/'+idx).remove().then(()=>{
        Alert.alert("찜 해제 완료!");
        reload()
      })
    } 


      

LikeCard.js --> 서버에서 데이터 삭제 부분

    import React from 'react';
    import {View, Image, Text, StyleSheet,TouchableOpacity,Alert} from 'react-native'
    import  Constants  from 'expo-constants';
    import {firebase_db} from '../firebaseConfig'

    //MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
    export default function LikeCard({content,reload,navigation}){

      const remove = (idx)=>{
      const user_id = Constants.installationId;
      firebase_db.ref('/like/'+user_id+'/'+idx).remove().then(()=>{
          Alert.alert("찜 해제 완료!");
          reload()
        })
      } 


        return(
            //카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
            <View style={styles.container}>

            <View style={styles.card} >
                <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>
            </View>

            <View style={styles.buttonContainer} >
              <TouchableOpacity style={styles.detailButton} onPress={()=>navigation.navigate('DetailPage',{idx:content.idx})} >
                <Text style={styles.detailText}>자세히보기</Text>

              </TouchableOpacity>

              <TouchableOpacity style={styles.deleteButton} onPress={()=>remove(content.idx)} >
                <Text style={styles.deleteText}>찜 해제</Text>

              </TouchableOpacity>

             </View>
            </View>
        )
    }


    const styles = StyleSheet.create({

      container:{
        flex:1

      },

        card:{
          flex:1,
          flexDirection:"row",
          margin:10,
          borderBottomWidth:0.5,
          borderBottomColor:"#eee",
          paddingBottom:10
        },
        cardImage: {
          flex:1,
          width:100,
          height:100,
          borderRadius:10,
        },
        cardText: {
          flex:2,
          flexDirection:"column",
          marginLeft:10,
        },
        cardTitle: {
          fontSize:20,
          fontWeight:"700"
        },
        cardDesc: {
          fontSize:15
        },
        cardDate: {
          fontSize:10,
          color:"#A6A6A6",
        },
        buttonContainer:{
          flex:1,
          flexDirection:"row",
          alignSelf:"center"

        },
        detailButton:{
          borderWidth:2,
          borderColor:"#c09",
          marginLeft:120,
          padding:10,
          width:100,
          borderRadius:10


        },
        deleteButton:{
          borderWidth:2,
          borderColor:"#c09",
          marginLeft:20,
          padding:10,
          width:100,
          borderRadius:10

        },
        detailText:{
          textAlign:"center",
          color:"#c09"

        },
        deleteText:{
          textAlign:"center",
          color:"#c09"

        }
    });
    

데이터 삭제 부분

   const remove = (idx)=>{
  const user_id = Constants.installationId;
  firebase_db.ref('/like/'+user_id+'/'+idx).remove().then(()=>{
      Alert.alert("찜 해제 완료!");
      reload()
    })
  } 
profile
ㅎㅎ

0개의 댓글