반원 블로그

1회차 - 04 react native 날씨 앱 따라 만들기(3), 지역 가져오기 본문

2018~/react native

1회차 - 04 react native 날씨 앱 따라 만들기(3), 지역 가져오기

반원_SemiCircle 2020. 6. 29. 21:39

계속 이어서 노마드코더 니콜라스의 React Native Weather를 따라해보도록 하자. 

영상 #1 2 Getting the Location부터 시작합니다.

리액트 네이티브의 Geolocation API

리엑트 네이티브 문서에서 geolocation 키워드를 검색해서 찾는다.

The Geolocation API extends the Geolocation web spec.

As a browser polyfill, this API is available through the navigator.geolocation global - you do not need to import it

(구글 번역)
Geolocation API는 Geolocation 웹 사양을 확장합니다 .
브라우저 폴리 필로이 API는 navigator.geolocation글로벌을 통해 사용 가능 하므로 필요하지 않습니다 import.

navigator.geolocation통해 사용가능하며 임포트할 필요가 없다는 내용입니다.
그런데 사용가능한 메소드가 약한 편입니다.

  • setRNConfiguration
  • requestAuthorization
  • getCurrentPosition : 현재 위치 가져오기
  • watchPosition : 위치 지켜보기
  • clearWatch : 위치 보기 지역 해제
  • stopObserving : 관찰 정지

그래도 위치만 가져오면 되기때문에 getCurrentPosition를 사용할 수 있겠습니다.

Expo의 Geolocation API

expo의 location은 좀더 다양하게 기능 제공을 한다.

예로 권한(permission)인증 받거나, 기능을 enable, disable하거나, 현재 위치는 물론 얻을 수 있고, 위치 탐색할 수도 있고, gps또는 network가 사용가능한지 알려주거나, 주소문자열로 위도 경도를 반환해주거나 그 반대로 해주거나, background location(자동 위치 추적)을 할 수 있거나, 사용자가 어떤 지역에 들어갔을 때, 떠났을 때를 알려주거나(Geofencing).

이렇게 기능이 많지만 기본 설치가 되어있지않다(이런 것들이 기본적으로 있으면 용량이 크자나!)
그래서 추가 설치를 해줘야한다.

여기선 expo install expo-location로 터미널에 입력해보자.

Expo의 Geolocation API 사용하기

참조(import)를 해서 코드 작성을 해보자. 사용방법은 아래를 참고

또한 그냥 테스트로 제대로 작동하는 지 확인하려는 목적으로
export default function App()를 class로 변경하고, 이제 render를 기본적으로 넣어주도록 하자.
다음 코드가 오류없는지까지 확인

import React from 'react';
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {

    render(){
        return <Loading/>;
    }
}

지역정보 받아오기 Location.getCurrentPositionAsync(options)

Location.getCurrentPositionAsync(options) 는 await functionality라고한다(이름에 Async가 들어가는데?!?)
await는 "기다려"란 뜻이고 지역정보도 가져올때까지 기다리기 때문이라는 듯..

지역 정보를 가져오는 함수를 만들면서, 아래처럼 작성해보자.

App.js

import React from 'react';
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // 함수 만들기
    geoLocation = async() => {
        const location = await Location.getCurrentPositionAsync(options);
        console.log(location);
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        return <Loading/>;
    }
}

이제 option 을 찾아보자.

그냥 default로 해도 동작할 것 같으니 option을 비우고 오류가 안나는지만 확인

App.js

import React from 'react';
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // 함수 만들기
    geoLocation = async() => {
        const location = await Location.getCurrentPositionAsync();
        console.log(location);
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        return <Loading/>;
    }
}

아래 보면 사용자에게 권한을 요청해야한다는 문구가 나온다.

권한 인증받기 Location.requestPermissionsAsync()

이것 역시 Async라는 단어가 있으니 await가 필요하다고 판단할 수 있다.
인증이 되었을 때의 처리와 안되었을 때 처리를 try catch 문법으로 분기설정해보자.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            console.log(response);
            const location = await Location.getCurrentPositionAsync();
            console.log(location);
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        return <Loading/>;
    }
}

아이폰인 경우도 비슷한 창이 나오는데 반드시 Always Allow 를 클릭하자. Don't Allow을 누르면 아이폰은 2번 다시 안물어보기때문에 setting에서 수동으로 allow시켜줘야한다.

안드로이드도 Allow를 클릭하면 된다.

터미널을 보면 다음처럼 지역정보에 대한 데이터가 나온다.

ES6문법을 이용해서 latitude, longitude 가져오기

ES6 문법에서 배운 객체 비구조화 문법을 사용해서 coords 뽑고, latitude, longitude를 뽑자.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            // console.log(response);
            const location = await Location.getCurrentPositionAsync();
            console.log(location);
            const {coords} = location;
            console.log(coords.latitude, coords.longitude);
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        return <Loading/>;
    }
}

이 코드는 latitude와 longitude를 가져오기위한 코드고, 이를 더 확실하게 줄이면

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            const {coords : {latitude, longitude}}  = await Location.getCurrentPositionAsync();
            console.log(latitude, longitude);
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        return <Loading/>;
    }
}

이제 이후 코드는 위치 정보를 날씨 API에 전송하여 날씨 정보를 응답받으면 된다.

state 변수 만들기

로딩 상태를 확인하는 state변수를 만들자.

render를 할 때 isLoading이 true일 때만 제대로 반환하고, 아니면 null을 반환하도록 만든다.

그리고 [권한 인증]-> [날씨 정보가져오기]-> [날씨 데이터API요청]-> [화면 처리]가 끝나면 로딩에서 넘어가도록 thie.setState({ isLoading:false });를 해야한다.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'

export default class extends React.Component {
    // state
    state = {
        isLoading : true
    };

    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            const {coords : {latitude, longitude}}  = await Location.getCurrentPositionAsync();
            console.log(latitude, longitude);

            // send weather api

            // 위 작업 전부 처리되면 로딩화면 종료 
            this.setState({ isLoading:false });
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        const { isLoading } = this.state;
        return isLoading ? <Loading/> : null;
    }
}

openWeatherApi 이용하기

여기는 파이썬으로 할 때 이미 해봐서 익숙하다.

API key를 복사해서 App.js에서 const로 만든다.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'

const API_KEY = "API키 정보";

export default class extends React.Component {
    // state
    state = {
        isLoading : true
    };

    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            const {coords : {latitude, longitude}}  = await Location.getCurrentPositionAsync();
            console.log(latitude, longitude);

            // send weather api

            // 위 작업 전부 처리되면 로딩화면 종료 
            this.setState({ isLoading:false });
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        const { isLoading } = this.state;
        return isLoading ? <Loading/> : null;
    }
}

이미 위치, 경도를 아니 요청할 때도 위치 경도로 요청하는 방법으로 문서를 찾아보면

API 요청 데이터는 JSON 형식일 건데, 이를 fetch하기 위해서 Axios를 설치하자. (그럼 편하다!)

  • npm install axios
  • yarn add axios

이후 axios import를 해준다. import axios from 'axios';

일단 날씨 API 요청하는 함수 getWeather의 폼부터 만들자.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'
import axios from 'axios';

const API_KEY = "api key";

export default class extends React.Component {
    // state
    state = {
        isLoading : true
    };

    // define get openweather api function
    getWeather = async(latitude, longitude) =>{

    }

    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            const {coords : {latitude, longitude}}  = await Location.getCurrentPositionAsync();
            console.log(latitude, longitude);

            // send weather api call
            this.getWeather(latitude, longitude);

            // 위 작업 전부 처리되면 로딩화면 종료 
            this.setState({ isLoading:false });
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        const { isLoading } = this.state;
        return isLoading ? <Loading/> : null;
    }
}

axios를 이용해서 웹 요청을 할 것입니다.
그런데 웹 요청 url을 적을 때 ` (백틱)을 이용합니다. 왜냐하면 lon, lat, appid의 값에 변수를 넣어줘야하기 때문입니다.

import React from 'react';
import {Alert} from 'react-native'
import Loading from "./Loading";
import * as Location from 'expo-location'
import axios from 'axios';

const API_KEY = "api key";

export default class extends React.Component {
    // state
    state = {
        isLoading : true
    };

    // define get openweather api function
    getWeather = async(latitude, longitude) =>{
        const {data} = await axios.get(
            `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}`
        );
        console.log(data);
    }

    // 함수 만들기
    geoLocation = async() => {
        try{
            const response = await Location.requestPermissionsAsync();
            const {coords : {latitude, longitude}}  = await Location.getCurrentPositionAsync();
            console.log(latitude, longitude);

            // send weather api call
            this.getWeather(latitude, longitude);

            // 위 작업 전부 처리되면 로딩화면 종료 
            this.setState({ isLoading:false });
        } catch(error){
            // 사용자가 허용안하면 위 코드에서 에러가 나고 그럼 여기가 실행
            Alert.alert("Can't find you.", "So sad");
        }        
    }

    componentDidMount(){
        this.geoLocation();
    }
    render(){
        const { isLoading } = this.state;
        return isLoading ? <Loading/> : null;
    }
}

여기까지 #1 4 Getting the weather까지 마무리 지었다. 이제 웹 디자인인 #2 0 Displaying Temperature 부분부터 진행하자.

Comments