인프런 커뮤니티 질문&답변

오영택님의 프로필 이미지
오영택

작성한 질문수

[2024] 비전공자도 가능한 React Native 앱 개발 마스터클래스

레이아웃 및 정보 구성하기[1]

섹션5. 날씨 앱 expo 버전

해결된 질문

작성

·

11

2

확실히 expo 버전으로 프로젝트를 생성하면, 영상처럼 진행이 되지 않습니다 ㅠㅠ

 

프로젝트 설치 및 실행 과정은 다음과 같습니다.

기종: Android

  1. npx create-expo-app <앱 이름> --template

  2. 세 번째(blank) :typescript 선택

  3. npx expo start를 실행

  4. expo 앱에서 QR 코드로 보기

강의와 달리, expo로 빌드하셨다면

npx expo install expo-location를 설치해주신 다음에

useEffect 함수 부분을 다음과 같이 변경해주면 됩니다.
(Expo는 자체 위치 서비스 API를 제공하므로, @react-native-community/geolocation 대신 expo-location을 사용해야 합니다.)

useEffect(() => {
  const getLocation = async () => {
    try {
      // 위치 권한 요청
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setError('위치 권한이 거부되었습니다');
        setLoading(false);
        return;
      }

      // 현재 위치 가져오기
      let location = await Location.getCurrentPositionAsync({});
      const { latitude, longitude } = location.coords;
      fetchWeather(latitude, longitude);
    } catch (err) {
      setError(err.message);
      setLoading(false);
    }
  };

  getLocation();
}, []);

다음으로

OpenWeatherMap API는 기본적으로 켈빈 온도를 반환합니다. 따라서 섭씨로 변환하는 코드를 추가해야 합니다.

각자 가져오신 API 값 뒤에 &units=metirc 를 추가해주시면 됩니다.

 

전체 코드는 다음과 같습니다.

import { StatusBar } from 'expo-status-bar';
import { useEffect, useState } from 'react';
import { ActivityIndicator, Text, View } from 'react-native';
import styled from 'styled-components/native';
import * as Location from 'expo-location';

const Container = styled.View`
  align-items: center;
  margin-top: 40px;
  background-color: #222222;
  flex: 1;
`;

const MainTemp = styled.Text`
  font-size: 80px;
  color: white;
`;

const Addition = styled.View`
  background-color: #aeaeae;
  width: 150px;
  height: 150px;
  margin: 15px;
  align-items: center;
  justify-content: center;
  border-radius: 15px;
`;

const App = () => {
  const [weatherData, setWeatherData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const getLocation = async () => {
      try {
        // 위치 권한 요청
        let { status } = await Location.requestForegroundPermissionsAsync();
        if (status !== 'granted') {
          setError('위치 권한이 거부되었습니다');
          setLoading(false);
          return;
        }

        let location = await Location.getCurrentPositionAsync({});
        const { latitude, longitude } = location.coords;
        fetchWeather(latitude, longitude);
      } catch (err) {
        setError(err.message);
        setLoading(false);
      }
    };

    getLocation();
  }, []);

  const fetchWeather = async (latitude, longitude) => {
    try {
      const response = await fetch(
        `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=<<개인 API값>>&units=metric`
      );
// <<>>는 지우셔야 합니다.
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      const data = await response.json();
      setWeatherData(data);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <Container>
        <ActivityIndicator size="large" color="#ffffff" />
      </Container>
    );
  }

  if (error) {
    return (
      <Container>
        <Text
          style={{ color: 'white', fontSize: 20 }}
        >{`Error: ${error}`}</Text>
      </Container>
    );
  }

  if (!weatherData) {
    return (
      <Container>
        <Text style={{ color: 'white', fontSize: 20 }}>No data available</Text>
      </Container>
    );
  }

  const {
    main: { temp, feels_like, humidity, temp_max, temp_min },
    wind: { speed },
    weather,
  } = weatherData;

  return (
    <Container>
      <StatusBar />
      <Text style={{ fontSize: 20, marginTop: 40, color: 'white' }}>
        {weatherData.name}
      </Text>
      <MainTemp>{Math.round(temp)}℃</MainTemp>
      <Text style={{ fontSize: 24, color: 'white' }}>{weather[0].main}</Text>

      <View style={{ flexDirection: 'row' }}>
        <Addition>
          <Text
            style={{
              color: 'white',
              fontSize: 20,
              marginTop: -40,
              marginBottom: 30,
            }}
          >
            체감 온도
          </Text>
          <Text style={{ color: 'white', fontSize: 18 }}>
            {Math.round(feels_like)}℃
          </Text>
        </Addition>
        <Addition>
          <Text
            style={{
              color: 'white',
              fontSize: 20,
              marginTop: -40,
              marginBottom: 30,
            }}
          >
            습도
          </Text>
          <Text style={{ color: 'white', fontSize: 18 }}>{humidity}%</Text>
        </Addition>
      </View>

      <View style={{ flexDirection: 'row' }}>
        <Addition>
          <Text
            style={{
              color: 'white',
              fontSize: 20,
              marginTop: -40,
              marginBottom: 30,
            }}
          >
            최고/최저 온도
          </Text>
          <Text style={{ color: 'white', fontSize: 18 }}>
            {Math.round(temp_max)}℃/{Math.round(temp_min)}℃
          </Text>
        </Addition>
        <Addition>
          <Text
            style={{
              color: 'white',
              fontSize: 20,
              marginTop: -40,
              marginBottom: 30,
            }}
          >
            풍속
          </Text>
          <Text style={{ color: 'white', fontSize: 18 }}>{speed} m/s</Text>
        </Addition>
      </View>
      <View></View>
    </Container>
  );
};

export default App;

 

답변 1

0

안녕하세요, 인프런 AI 인턴입니다. 오영택님.

Expo를 이용하여 프로젝트를 생성했을 때와 강의에서 다루는 내용 사이에 발생할 수 있는 차이점에 대해 설명해주셔서 감사합니다. React Native와 Expo 환경에서는 약간의 설정 차이가 존재할 수 있어, 이로 인해 혼동이 생길 수 있습니다.

Expo 프로젝트에서의 위치 서비스 설정

Expo를 사용하면 위치 서비스 관련 API가 더욱 간단하게 제공됩니다. expo-location 모듈을 사용해주셨듯, Expo 환경에서는 @react-native-community/geolocation 대신 expo-location을 통해 위치 데이터를 관리하는 것이 올바릅니다.

  1. 위치 권한 및 위치 데이터 가져오기:

    • Location.requestForegroundPermissionsAsync()를 호출하여 앱이 위치 데이터를 얻을 수 있도록 사용자에게 권한을 요청합니다.
    • 위치가 승인되면, Location.getCurrentPositionAsync()를 사용하여 현재 위치를 획득합니다.
  2. API를 통한 날씨 데이터 가져오기:

    • OpenWeatherMap API를 사용하여 날씨 정보를 받아옵니다. 여기서 주의할 점은 온도를 섭씨(Celcius)로 표시하기 위해 &units=metric 파라미터를 추가해야 한다는 것입니다.

참고할 수 있는 유사 질문들

아래 링크에서도 비슷한 문제에 대한 토론이 이루어졌으니 도움이 될 것입니다:

  1. expo로 설치해도 되나요?

    • 내용 요약: Expo와 React Native의 설치 및 초기 설정 방법에 대한 안내가 이루어졌습니다. Expo에서 프로젝트 생성 시 필수적인 라이브러리 설정에 대한 도움말이 포함되어 있습니다.
  2. 프로젝트 생성에 대해서?

    • 내용 요약: Expo가 아닌 경우의 다른 프로젝트 생성 방법에 대한 설명을 담고 있습니다.

오영택님께서 주신 코드와 설명은 많은 다른 사용자 분들께도 유용한 팁이 될 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

오영택님의 프로필 이미지
오영택

작성한 질문수

질문하기