커뮤니티
포인트
쿠폰
내 강의실
국비 신청 내역
증명서
계정
로그아웃
학습 질문
개발 일지
나의 활동
답변 완료
4-13 숙제 강의 꿀팁찜 누르면 찜 리스트가 보이다가도 안보여요
앱개발 종합반 - 리액트 네이티브
4주차
북마크
임*호
댓글
4
추천
0
조회수
19
조회수
19
답변 완료

4-13강 숙제5 부분입니다. 메인페이지에서 꿀팁찜 누르면 찜한 당연히 리스트가 보여야 합니다.


그런데 이 꿀팁찜이 안보일 때가 너무 많아요. 예를 들어 찜페이지 들어가서 '찜 해제' 버튼을 누르고 메인으로 나왔다가 다시 꿀팁찜에 들어가면 찜 리스트가 하나도 안 보일 때가 많습니다.


수도 없이 많이 시도해 본 결과 서버에서 찜 데이터가 바뀌면 그 다음에는 찜 리스트가 아예 안 보이게 되는 것을 알게 됐습니다.

스파르타 즉문즉답


스파르타 즉문즉답

이렇게 서버에는 찜 데이터가 있는데 앱화면에서는 나오지 않고 있습니다. 계속 여러개 찜을 누르다 보면 어느순간 찜리스트가 나타나기도 합니다. 하지만 그러다 또 해제하거나 추가해서 서버의 데이터가 바뀌면 찜 데이터가 없다고 뜹니다. 며칠째 계속 이러고 있습니다.

찜 추가를 하든 해제를 하든 바로바로 반영되게 하는 방법을 알려주시기 부탁드립니다. 지금은 서버 데이터 한번 바뀌면 바로 데이터가 없다고 뜨는 앱이 되어버렸어요.



MainPage.js

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


const main = 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png'
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";
import axios from "axios"
import {firebase_db} from "../firebaseConfig"


export default function MainPage({navigation,route}) {
  //useState 사용법
  //[state,setState] 에서 state는 이 컴포넌트에서 관리될 상태 데이터를 담고 있는 변수
  //setState는 state를 변경시킬때 사용해야하는 함수


  //모두 다 useState가 선물해줌
  //useState()안에 전달되는 값은 state 초기값
  const [state,setState] = useState([])
  const [cateState,setCateState] = useState([])
  //날씨 데이터 상태관리 상태 생성!
  const [weather, setWeather] = useState({
    temp : 0,
    condition : ''
  })


  //하단의 return 문이 실행되어 화면이 그려진다음 실행되는 useEffect 함수
  //내부에서 data.json으로 부터 가져온 데이터를 state 상태에 담고 있음
  const [ready,setReady] = useState(true)


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


  const getLocation = async () => {
    //수많은 로직중에 에러가 발생하면
    //해당 에러를 포착하여 로직을 멈추고,에러를 해결하기 위한 catch 영역 로직이 실행
    try {
      //자바스크립트 함수의 실행순서를 고정하기 위해 쓰는 async,await
      await Location.requestForegroundPermissionsAsync();
      const locationData= await Location.getCurrentPositionAsync();
      console.log(locationData)
      console.log(locationData['coords']['latitude'])
      console.log(locationData['coords']['longitude'])
      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)
      const temp = result.data.main.temp; 
      const condition = result.data.weather[0].main
      
      console.log(temp)
      console.log(condition)


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


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


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


  //data.json 데이터는 state에 담기므로 상태에서 꺼내옴
  // let tip = state.tip;
  let todayWeather = 10 + 17;
  let todayCondition = "흐림"
  //return 구문 밖에서는 슬래시 두개 방식으로 주석
  return ready ? <Loading/> :  (
    <ScrollView style={styles.container}>
      <StatusBar style="light" />
      {/* <Text style={styles.title}>나만의 꿀팁</Text> */}
       <Text style={styles.weather}>오늘의 날!씨: {weather.temp + '°C ' + weather.condition} </Text>
        <TouchableOpacity style={styles.AboutPage} onPress={()=>{navigation.navigate('AboutPage')}}>
          <Text style={styles.middleButtonText}>소개 페이지</Text>
        </TouchableOpacity>
      <Image style={styles.mainImage} source={{uri: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((content1,i3)=>{
            return (<Card content8={content1} key={i3} navigation2={navigation}/>)
          })
        }
        
      </View>
   
    </ScrollView>)
}


const styles = StyleSheet.create({
  container: {
    //앱의 배경 색
    backgroundColor: '#fff',
  },
  title: {
    //폰트 사이즈
    fontSize: 20,
    //폰트 두께
    fontWeight: '700',
    //위 공간으로 부터 이격
    marginTop:50,
    //왼쪽 공간으로 부터 이격
    marginLeft:20
  },
weather:{
    alignSelf:"flex-end",
    paddingRight:20
  },
  mainImage: {
    //컨텐츠의 넓이 값
    width:'90%',
    //컨텐츠의 높이 값
    height:200,
    //컨텐츠의 모서리 구부리기
    borderRadius:10,
    marginTop:20,
    //컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
    //각 속성의 값들은 공식문서에 고대로~ 나와 있음
    alignSelf:"center"
  },


  AboutPage: {
    width:120,
    height:50,
    padding:15,
    backgroundColor:"#fdc453",
    borderColor:"deeppink",
    borderRadius:15,
    marginTop: 10,
    margin: 10,
    alignSelf:"flex-end",
  },
  middleContainer:{
    marginTop:20,
    marginLeft:10,
    height:60
  },
  middleButtonAll: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#20b2aa",
    borderColor:"deeppink",
    borderRadius:15,
    margin:7
  },
  middleButton01: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#fdc453",
    borderColor:"deeppink",
    borderRadius:15,
    margin:7
  },
  middleButton02: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#fe8d6f",
    borderRadius:15,
    margin:7
  },
  middleButton03: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#9adbc5",
    borderRadius:15,
    margin:7
  },
  middleButton04: {
    width:100,
    height:50,
    padding:15,
    backgroundColor:"#f886a8",
    borderRadius:15,
    margin:7
  },
  middleButtonText: {
    color:"#fff",
    fontWeight:"700",
    //텍스트의 현재 위치에서의 정렬 
    textAlign:"center"
  },
  middleButtonTextAll: {
    color:"#fff",
    fontWeight:"700",
    //텍스트의 현재 위치에서의 정렬 
    textAlign:"center"
  },
  cardContainer: {
    marginTop:10,
    marginLeft:10
  },



});





LikePage.js

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import Loading from '../components/Loading';


const main = 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png'
import LikeCard from '../components/LikeCard';
import * as Application from 'expo-application';
const isIOS = Platform.OS === 'ios';
import {firebase_db} from "../firebaseConfig"



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


  const [tip, setTip] = useState([])
  const [ready,setReady] = useState(true)



  useEffect(()=>{
     
    //뒤의 1000 숫자는 1초를 뜻함
    //1초 뒤에 실행되는 코드들이 담겨 있는 함수


      navigation.setOptions({
        title:'꿀팁 찜'
    })
    getLike()
  },[])


  const getLike = async () => {
    let userUniqueId;
        if(isIOS){
        let iosId = await Application.getIosIdForVendorAsync();
            userUniqueId = iosId
        }else{
            userUniqueId = await Application.androidId
        }


        console.log(userUniqueId)
        firebase_db.ref('/like/'+userUniqueId).once('value').then((snapshot) => {
          console.log("파이어베이스에서 데이터 가져왔습니다!!")
          let tip = snapshot.val();
          if(tip && tip.length >= 0){
            setTip(tip)
            setReady(false)
        }      
      })
   }


  return ready ? <Loading/>: (
    <ScrollView style={styles.container}>
         {
          tip.map((content1,i3)=>{
            return (<LikeCard content8={content1} key={i3} navigation2={navigation} tip={tip} setTip={setTip}/>)
          })
        }
    </ScrollView>)
}


const styles = StyleSheet.create({
  container: {
    //앱의 배경 색
    backgroundColor: '#fff',
  },


});





LikeCard.js

import React from "react";
import { View, Image, Text, StyleSheet, TouchableOpacity, Alert } from "react-native";
import * as Linking from 'expo-linking';
import {firebase_db} from "../firebaseConfig"
const isIOS = Platform.OS === 'ios';
import * as Application from 'expo-application';
//MainPage로 부터 navigation2 속성을 전달받아 Card 컴포넌트 안에서 사용
export default function LikeCard({ content8, navigation2, tip, setTip }) {


  const detail = () => {
    navigation2.navigate('DetailPage',{idx:content8.idx})
}


  const remove = async(cidx) => {        
    let userUniqueId;
    if(isIOS){
    let iosId = await Application.getIosIdForVendorAsync();
        userUniqueId = iosId
    }else{
        userUniqueId = await Application.androidId
    }


    console.log(userUniqueId)
    firebase_db.ref('/like/'+userUniqueId+'/'+ cidx).remove().then(function(){
        Alert.alert("삭제 완료!");


        let result = tip.filter((data,i)=>{
          return data.idx !== cidx
        })
        console.log(result)
        setTip(result)


      })  
}


  return (
    //카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
    <View>
      <TouchableOpacity style={styles.card}>
        <Image style={styles.cardImage} source={{ uri: content8.image }} />
        <View style={styles.cardText}>
          <Text style={styles.cardTitle} numberOfLines={1}>
            {content8.title}
          </Text>
          <Text style={styles.cardDesc} numberOfLines={3}>
            {content8.desc}
          </Text>
          <Text style={styles.cardDate}>{content8.date}</Text>
          <View style={styles.buttonGroup}>
            <TouchableOpacity style={styles.button}>
              <Text style={styles.buttonText} onPress={() => detail()}>
                자세히보기
              </Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => remove(content8.idx)}
            >
              <Text style={styles.buttonText}>찜해제</Text>
            </TouchableOpacity>
          </View>
        </View>
      </TouchableOpacity>
    </View>
  );
}


const styles = StyleSheet.create({
  card: {
    flex: 1,
    flexDirection: "row",
    margin: 10,
    borderBottomWidth: 0.5,
    borderBottomColor: "#eee",
    paddingBottom: 10,
  },
  cardImage: {
    flex: 1,
    width: 100,
    height: 120,
    borderRadius: 10,
  },
  cardText: {
    flex: 2,
    flexDirection: "column",
    marginLeft: 10,
  },
  cardTitle: {
    fontSize: 20,
    fontWeight: "700",
  },
  cardDesc: {
    fontSize: 15,
  },
  cardDate: {
    fontSize: 10,
    color: "#A6A6A6",
  },
  buttonGroup: {
    flexDirection:"row",
  },
  
  button: {
    width: 95,
    marginTop: 5,
    marginRight: 10,
    marginLeft: 10,
    padding: 10,
    borderWidth: 1,
    borderColor: "deeppink",
    borderRadius: 7,
  },
  buttonText:{
    color:'deeppink',
    textAlign:'center'
}
});


취소
 공유
취소
댓글 0
댓글 알림
나의얼굴