24/4/20 react-native 날씨 어플 만들어보기

2024. 4. 20. 23:19카테고리 없음

흐음... 앱만들기를 한번 바워보자구요  하하하하하 

일단 react-native는 expo라는 라이브러리가 쉽게 부가적인것을 제공해서 최적화 해준다는구먼요

노마드코더 클론코딩 오늘 해본것들을 복습해보자구~

expo 를 인스톨 하고 expo init 명령어를 통해 react-native 프레임을 만듭니다.

근데 이게 depricated라고 뜨는것을 보니 업데이트 안하나봄 앞으로는 뭘로해야하는 거징??

날씨알려주는 어플

 

<App.js>

import { StatusBar } from "expo-status-bar";  // 스마트폰 상단에 알림등을 보여주는 바를 나타냄
import { useEffect, useState } from "react";   //react의 훅들을 차용하나봄
import {
  ScrollView,                              //react-native는 모든 컴포넌트들을 import해서 쓰나 봄
  Dimensions,                                //react랑은 다르군요 호호
  StyleSheet,
  ActivityIndicator,
  Text,
  View,
} from "react-native";
import * as Location from "expo-location";          //expo 로케이션이라는 라이브러리 인스톨받아야함
import { Fontisto } from "@expo/vector-icons";                  //구름사진과 같은 아이콘을 받아올수 있음
const { width: screenWidth } = Dimensions.get("window");    //Dimensions를 통해 현재 화면의 크기정보를 가져옴
const API_KEY = "a5665c117c73b1089bdaec9b1f9";   //날씨 데이터를 받아오기위한 APIKEy

const icons = {                  //키값에 따른 value의 아이콘을 가져오기위한 오브젝트화
  Clouds: "cloudy",
  Rain: "rains",
  Clear: "day-sunny",
  Snow: "snow",
  Drizzle: "rain",
  Thunderstorm: "lightning",
  Atmosphere: "cloudy-gusts",
};
export default function App() {                              //기본 구조는 react와 컴포넌트형식이 같다.
  const [city, setCity] = useState("...loading");        //useState 오랜만에 보는 기분이넹 ㅎㅎ 
  const [days, setDays] = useState([]);              //도시이름을 담을 city  비동기 통신 data를 담을 days
  const [ok, setOk] = useState(true);                //상태정보를 담을 ok로 나눈다.
  const ask = async () => {                        //비동기 통신의 시작함수
    const { granted } = await Location.requestForegroundPermissionsAsync();  //Location이라고 명명한
    if (!granted) {                                                                          //것에서 요 매서드를 호출한다.
      setOk(false);                                     //해당 오브젝트에는 승인되었는지 여부가 들었는데
    }                                               //승인 안됬으면 안됐다고 스테이트 변경해준다.
    const {
      coords: { latitude, longitude },          //승인 되었으면 일단 오브젝트 형식으로 위치정보를
    } = await Location.getCurrentPositionAsync({ accuracy: 5 });         //요 매서드로 받아올수 있다.
    const location = await Location.reverseGeocodeAsync(       //awate로 다 되길 기다렸다가
      {                                                                                       //위도 경도 받은게 첫번째 인자로 들가고
        latitude,
        longitude,
      },
      { useGoogleMaps: false }                                    //구글맵을 안쓴다는 상태를 알리는 인자? ㅋㅋ
    );
    setCity(location[0].city);            //await 달려있응께 다 끝나면 setCity가 이루어 지고

    const URL = `https://api.openweathermap.org/data/2.5/forecast?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`; // 비동기 통신을 할 url정보
    const res = await fetch(URL);                                             //위도경도 apikey가 필요했다.
    const json = await res.json();                       //fetch로 data가져오고 json형식에서 파싱해주고
    setDays(json.list);                                      //해당 data중에서 list를 days라는 스테이트에 보관한다.
    //   const resres = json.list.map((i) => {
    //     return i.weather;
    //   });
    //   console.log(resres);
  };
  useEffect(() => {         //useEffect 훅으로 첫 마운트시에 비동기 호출 수행하도록 조치
    ask();
  }, []);
  return (                                                        //return 안에 jsx형식으로 쓰는 것도 react랑 똑같다.
    <View style={styles.container}>                    //태그가 다양하지는 않는데 전부 view로 하고
      <View style={styles.city}>
        <Text style={styles.cityName}>{city}</Text>     //글자만 text라고 한다. 호호 그렇구먼
      </View>                                                        //styles 어쩌고 하면서 밑에서 설정한 css를 가져온다.
      <ScrollView            //react와 달리 react-native는 자동적으로 스크롤이 생기지 않는다.
        horizontal                                  //요 스크롤 뷰라는 태그를 사용해야함
        pagingEnabled                                               //호리즌털을 가로스크롤링
        showsHorizontalScrollIndicator={false}            //페이징이네블드는 페이지별로 넘어가게함
        contentContainerStyle={styles.weather}          //요 태그에 style변화주려면 요 속성을 써야한다고함
      >
        {days.length === 0 ? (                     //삼항연산자로 깔쌈하게 비동기 통신결과값이 없다면
          <View style={{ ...styles.day, alignItems: "center" }}>
            <ActivityIndicator></ActivityIndicator>          //요 로딩창 보여주는 태그가 보여지게 조치
          </View>
        ) : (
          days.map((item, idx) => {            //days라는 스테이트에 배열형식이 담겼으므로 익숙한 
            return (                                                            //map 매서드로 태그를 뿌려주자
              <View key={idx} style={styles.day}>         //귀찮응께 일단 키는 idx로 해두고
                <View                                                 //근데 얘네는 부모태그의 css를 자동으로 물려받지는 않나봄?
                  style={{ flexDirection: "row", justifyContent: "center" }}   //신기한게 기본적으로 flex-col이라서
                >                                                                                //방향 바꾸고 싶으면 row로 바꿔야됨
                  <Text style={styles.temp}>{item.main.temp}</Text>
                  <Fontisto                                                  //아이콘 쓰려고 임포트 해온 태그에서
                    name={icons[item.weather[0].main]}       //name을 일치시키면 해당 아이콘을 가져올수 있는데
                    size={60}                                               //아이콘 사이트가 머라머라 헀는데 흐음... 아몰랑
                    color="white"
                  ></Fontisto>
                </View>

                <Text style={styles.description}>{item.weather[0].main}</Text>
              </View>
            );
          })
        )}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({      //css 정의는 이런식으로 함 인라인으로 할수도 있는데
  container: {                                            //styleSheet으로 해야 자동완성도 되고 정리도 되고 좋음
    flex: 1,                                                //flex는 화면 내에서 비율로써 작동함
    backgroundColor: "tomato",
  },
  city: {
    flex: 1,

    justifyContent: "center",
    alignItems: "center",
  },
  cityName: {
    color: "black",
    fontSize: 68,
    fontWeight: "500",
  },
  weather: {
    backgroundColor: "teal",
  },
  day: {
    fontSize: 50,
    width: screenWidth,              //요건 위에서 dimention으로 가져온 화면크기를 적용 
    alignItems: "center",           //스마트폰 종류에 따라 가로세로 크기가 다르니 자주 쓸듯?
  },

  temp: {
    marginTop: -30,
    fontSize: 100,
  },
  description: {
    fontSize: 60,
  },
});

//복습 소감....

//react 와 비슷해서 익히는데 어려움은 없을것 같고 

//다 숙달하면 재밌는 앱 하나 만들어 봐야겠다. 호호