깡뇽

[ReactNative] 왕초보를 위한 React Native 101 (2) 본문

Web/ReactNative

[ReactNative] 왕초보를 위한 React Native 101 (2)

깡뇽 2022. 5. 16. 19:59
반응형

노마트코더에서 "왕초보를 위한 React Native 101"를 수강하며 공부한 부분들을 정리해보려고 한다.

 

#2.0 Snack

Snack 사이트로 웹에서 리액트네이티브코딩 가능.

 

#2.1 The Rules of Native

View는 컨테이너로서 웹의 div처럼 활용됨. -> import 필수!

<Text> 텍스트 컴포넌트로서 텍스트 표현을 위해 사용됨.

View는 style을 가짐. -> React js와 유사. 그러나 border과 같은 스타일 속성을 사용할 수 없음.

StyleSheet.create는 object를 생성. -> 자동 완성 기능을 제공. 스타일 컴포넌트를 정리해서 보기 좋음. (StyleSheet.create 표현 없이 ```const styles = { container: {스타일}, };```로 작성해도 style = {styles.container}는 작동하지만 컨테이너 안에서 코드 자동완성 기능이 지원되지 않음.

StatusBar는 서드파티 패키지임. -> <StatusBar style="auto" /> 상단바와 소통 가능. => auto를 light로 변경하면 상단바 사라짐.

 

#2.2 React Native Packages

API와 컴포넌트들이 사라지는 중. -> AsyncStorage 다운 후 사용.

 

#2.3 Third Party Packages

<컴포넌트>

View, StatusBar, Vibration 등

reactnative.directory/에서 원하는 storage 활용 가능. 

Expo SDK를 통해 다양하게 활용 가능. -> import { StatusBar } from 'expo-status-bar"; (기존 import { StatusBar } from "react-native";

 

#2.4 Layout System

레이아웃 -> Flexbox은 웹과 몇 기능이 다름. 기본적으로 상단에 위치.

<View style={{ flexDirection: "row" }}> 를 사용해서 가로로 배치. (기본값을 column)
 스크린 사이즈를 고려해서 width와 height를 사용하지 않음. -> <View style={{ flex: 1 }}> 사용.
 

#2.5 Styles

위치 정보(https://docs.expo.dev/versions/latest/sdk/location/)를 사용해서 날씨 정보를 API로 가져올 것이다.

1. 기본 View에 스타일 적용 & 텍스트 생성 

2. 컨테이너 2개로 구성하기 - city & weather

3. weather 컨테이너 구성 - 날짜와 날씨 정보 컨테이너

 

# 2.6 Styles part Two 

1. 스크롤 기능 - ScrollView

2. horizontal로 가로 스크롤 변경

3. 스크롤 기능에 스타일을 적용하고 싶다면 contentContainerStyle 사용

 

4. 화면 크기를 얻어서 활용 - Dimensions

내 화면 크기는 333이군.

이제 해당 화면 크기를 직접 받아서 활용하자.

5. 페이지 만들기 - pagingEnabled

6. 스크롤바 삭제하기 - showsHorizontalScrollIndicator

+ 전체 코드

import React from 'react';
import { View, Text, StyleSheet, ScrollView, Dimensions } from 'react-native';

const { width: SCREEN_WIDTH } = Dimensions.get("window");
//위와 동일 cosnt SCREEN_WIDTH = Dimensions.get("window").width;
console.log(SCREEN_WIDTH);

export default function App() {
  return <View style={styles.container}> 
    <View style={styles.container}>
      <View style={styles.city}>
        <Text style={styles.cityName}>Seoul</Text>
      </View>

      <ScrollView pagingEnabled
                  horizontal 
                  showsHorizontalScrollIndicator={false}
                  contentContainerStyle={styles.weather}>
        <View style={styles.day}>
          <Text style={styles.temp}>27</Text>
          <Text style={styles.description}>Sunny</Text>
        </View>
        <View style={styles.day}>
          <Text style={styles.temp}>27</Text>
          <Text style={styles.description}>Sunny</Text>
        </View>
        <View style={styles.day}>
          <Text style={styles.temp}>27</Text>
          <Text style={styles.description}>Sunny</Text>
        </View>
        <View style={styles.day}>
          <Text style={styles.temp}>27</Text>
          <Text style={styles.description}>Sunny</Text>
        </View>
      </ScrollView>
    </View>
  </View>;
}

const styles = StyleSheet.create({
  container: {
    flex: 1, 
    backgroundColor: "teal",
  },
  city: {
    flex: 1.2,
    justifyContent: "center",
    alignItems: "center",
  },
  cityName: {
    fontSize: 58,
    fontWeight: "500",
  },
  weather: {
    flex: 3,
  },
  day: {
    width: SCREEN_WIDTH,
    alignItems: "center",
  },
  temp: {
    marginTop: 50,
    fontWeight: "600",
    fontSize: 178,
  },
  description: {
    marginTop: -30,
    fontSize: 60,
  },
});

 

#2.7 Location

```expo install expo-location```을 입력하여 Location 기능을 사용할 수 있도록 한다. 

 

1. 권한 허용을 위한 코드 작성

const ask = async () => {

    const {granted} = await Location.requestForegroundPermissionsAsync();
    if(!granted) {
      setOk(false); //권한 요청 거절
    }
  };
 
2. 지역 정보 받기
const location = await Location.getCurrentPositionAsync({accuracy:5});
console.log(location);
이렇게 해서 확인해봐도 빈 {}만 출력됨. 왜인지는 모르겠다 ㅠㅠ

 

#2.8 Weather

https://openweathermap.org/api 해당 사이트 날씨 API를 사용할 것이므로 API 키를 발급(예전에 가입해뒀던 계정이있어서 왼쪽 상단 이름을 클릭한 후 My API keys를 클릭했더니 Key를 찾을 수 있었음) 받는다.

 

One Call API 문서로 이동해서 API call을 복사해서 사용한다. 

https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={API key} 

 

1. API를 통해 json을 받아오기

const response = fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&exclude=alerts&appid=${API_KEY}`);
    const json = await response.json();
    console.log(json);
-> 위에서 장소 받아오기가 안되가지고 이것도 안된다 ㅠㅠ
console.log(json.daily); 를 setDays(json.daily);로 바꾸면 날짜도 바로 적용 가능.
 
2. 스크롤뷰 코드 안에 적용.
{days.length === 0 ? "" : <View style={styles.day}></View>}
 
3. 로딩 추가
ActiviyIndicator를 import에 추가해주고, 스크롤뷰 코드를 마저 완성한다.
{days.length === 0 ? (
          <View style={styles.day}>
            <ActivityIndicator color="white" size="large" style={{ marginTop: 10 }}/>
          </View>
          ) : (
            <View style={styles.day}></View>
          )}

 

4. 실제 데이터 적용

{days.length === 0 ? (
          <View style={styles.day}>
            <ActivityIndicator color="white" size="large" style={{ marginTop: 10 }}/>
          </View>
          ) : (
            days.map((day, index) =>
              <View key={index} style={styles.day}>
                <Text style={styles.temp}>{day.temp.day}</Text>
                <Text style={styles.description}>{day.weather[0].main}</Text>
              </View>  
            )
          )}

 

5. 단위 변경을 위해서 api 부분에 &units=metric 추가하기

 

6. 온도 소수점 단위 변경

day.temp.day 대신에
parseFloat(day.temp.day).toFixed(1) 를 사용하면 소수점 뒤 한자리 사용.

7. 설명 텍스트 추가하고 스타일 적용

 

+ 전체코드

```

import React, { useEffect, useState } from 'react';
import * as Location from 'expo-location';
import { ViewTextActivityIndicatorStyleSheetScrollViewDimensions } from 'react-native';

const { width: SCREEN_WIDTH } = Dimensions.get("window");
//위와 동일 cosnt SCREEN_WIDTH = Dimensions.get("window").width;
console.log(SCREEN_WIDTH);

const API_KEY = "907895aed96a03a8a8559886054ee935";

export default function App() {
  const [city, setCity] = useState("Loading...");
  // const [location, setLocation] = useState();
 const [days, setDays] = useState([]);
  const [ok, setOk] = useState(true);
  const ask = async () => {
    const { granted } = await Location.requestForegroundPermissionsAsync();
    if(!granted) {
      setOk(false); //권한 요청 거절
    }
    const {
      coords: { latitude, longitude },
    } = await Location.getCurrentPositionAsync({accuracy:5});
    const location = await Location.reverseGeocodeAsync(
      { latitude, longitude }, 
      { useGoogleMaps: false }
    );
    setCity(location[0].city);
    const response = fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&exclude=alerts&appid=${API_KEY}&units=metric`);
    const json = await response.json();
    setDays(json.daily);
  };
  useEffect(() => {
    ask();
  }, [])
  return <View style={styles.container}> 
    <View style={styles.container}>
      <View style={styles.city}>
        <Text style={styles.cityName}>{city}</Text>
      </View>

      <ScrollView pagingEnabled
                  horizontal 
                  showsHorizontalScrollIndicator={false}
                  contentContainerStyle={styles.weather}>
        {days.length === 0 ? (
          <View style={styles.day}>
            <ActivityIndicator color="white" size="large" style={{ marginTop: 10 }}/>
          </View>
          ) : (
            days.map((day, index) =>
              <View key={index} style={styles.day}>
                <Text style={styles.temp}>{parseFloat(day.temp.day).toFixed(1)}</Text>
                <Text style={styles.description}>{day.weather[0].main}</Text>
                <Text style={styles.tinyText}>day.weather[0].description</Text>
              </View>  
            )
          )}
      </ScrollView>
    </View>
  </View>;
}

const styles = StyleSheet.create({
  container: {
    flex: 1
    backgroundColor: "teal",
  },
  city: {
    flex: 1.2,
    justifyContent: "center",
    alignItems: "center",
  },
  cityName: {
    fontSize: 58,
    fontWeight: "500",
  },
  weather: {
    flex: 3,
  },
  day: {
    width: SCREEN_WIDTH,
    alignItems: "center",
  },
  temp: {
    marginTop: 50,
    fontWeight: "600",
    fontSize: 178,
  },
  description: {
    marginTop: -30,
    fontSize: 60,
  },
  tinyText: {
    fontSize: 20,
  },
});

```

 

#2.9 Recap

State를 3개 생성했고, 가장 먼저 유저에게 권한을 허가받을 수 있도록 구현.

그리고 latitude와 longtitude로 장소를 받았음.

그리고 API를 사용해서 도시 정보를 받았고, city State에 저장.

json 타입으로 많은 정보를 response로 받아서 활용.

daily 정보를 setDays를 통해 days State에 저장.

해당 정보에서 날 각각을 받기 위해서 map을 사용해 줌.

 

#2.10 Icons

https://icons.expo.fyi/ 해당 사이트에서 아이콘을 찾아 볼 수 있음.

가장 먼저 import를 해주고, icons를 정의해준 뒤에 해당 값으로 icon을 동적으로 불러와서 적용 가능.

import { Fontisto } from '@expo/vector-icons';
const icons = {
  Clouds"cloudy",
  Clear"day-sunny",
  Snow"snow",
  Rain"rains",
  Drizzle"rain",
  Thunderstorm"lighting",
}
<Fontisto name={icons[day.weather[0].main]} size={68} color="white"/>

+ style을 그대로 가져오고 하나만 변경하고 싶다면, style={{ ...styles.day, alignItems: "center" }} 와 같이 활용 가능.

 

반응형