๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

react

React / openweatherapi ์‚ฌ์šฉํ•˜๊ธฐ

 

 

์–ด์ œ๋Š” openweathermap API๋กœ ํ˜„์žฌ ๋‚ด ์œ„์น˜์˜ 5์ผ๊ฐ„์˜ ๋‚ ์”จ๋ฅผ ๋ฐ›์•„์˜ค๊ณ ,

styled-components๋ฅผ ์‚ฌ์šฉํ•ด ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๋Š” ๊ณผ์ œ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ๋Š”๋ฐ

 

์—ฐ๋™ํ•˜๋Š”๋ฐ ์‹œ๊ฐ„์„ ๋งŽ์ด ์ผ์–ด์„œ ์ด๋ฒˆ ๊ธฐํšŒ์— ์ •๋ฆฌํ•ด๋‘๊ณ ์ž ํ•œ๋‹ค (์˜ˆ์ „์— ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ๋Š” ๋ฐ›์•„์™”๋Š”๋ฐ๋„... )

์ผ๋‹จ ์‚ฌ์šฉํ•ด์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ App.jsx์— ํ•œ๋ฒˆ์— ์ ์–ด๋†จ๋‹ค

 

 

App.jsx

๋”๋ณด๊ธฐ
import { useState, useEffect } from 'react';
import { styled, createGlobalStyle } from 'styled-components';

// styled-components ------------------

const Container = styled.div`
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

const Title = styled.h2`
  text-align: center;
  margin-bottom: 2em;
`;

const WeatherCardContainer = styled.ul`
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  justify-items: center;
  width: 100%;
  list-style: none;
  margin: 0 auto;
  padding: 20px;
  gap: 10px;
`;

const WeatherCard = styled.li`
  display: flex;
  width: 200px;
  height: 150px;
  justify-items: start;
  border-radius: 10px;
  border: 1px solid #eee;
  padding: 10px;
  flex-direction: column;
  justify-content: space-around;
`;

const WeatherCardTitle = styled.div`
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-around;
  img {
    width: 30px;
  }
`;

const WeatherCardContent = styled.div`
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
`;

const GlobalStyle = createGlobalStyle`
  * {
    margin : 0;
    padding : 0;
    box-sizing: border-box;
  }
`;

// styled-components ๋ ------------------

function App() {
  const [weather, setWeather] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // ์œ„์น˜ ์ •๋ณด ์š”์ฒญ
    navigator.geolocation.getCurrentPosition(
      (position) => {
        const latitude = position.coords.latitude;
        const longitude = position.coords.longitude;
        // const { latitude, longitude } = position.coords;
        const API_KEY = import.meta.env.VITE_WEATHER_API_KEY;

        // fetch ํ˜ธ์ถœ (Promise ์ฒด์ธ ์‚ฌ์šฉ)
        fetch(
          `https://api.openweathermap.org/data/2.5/forecast?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric&lang=kr`,
        )
          .then((res) => {
            if (!res.ok) {
              throw new Error('๋‚ ์”จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.');
            }
            return res.json();
          })
          .then((data) => {
            // 3์‹œ๊ฐ„ ๊ฐ„๊ฒฉ ๋ฐ์ดํ„ฐ ์ค‘์—์„œ ๋งค์ผ 12:00:00 ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋ง
            const dailyForecast = data.list.filter((item) =>
              item.dt_txt.includes('12:00:00'),
            );

            // ์›๋ณธ ๋ฐ์ดํ„ฐ์— list๋ฅผ ๋Œ€์ฒดํ•ด์„œ ์ €์žฅ
            setWeather({ ...data, list: dailyForecast });
          })
          .catch((err) => {
            setError(err.message);
          });
      },
      (err) => {
        setError(err.message);
      },
    );
  }, []);

  if (error) return <p>{error}</p>;

  return (
    <>
      <GlobalStyle />
      <Container>
        {weather ? (
          <>
            <Title>{weather.city.name} - 5Days Weather</Title>
            <WeatherCardContainer>
              {weather.list.map((item) => (
                <WeatherCard key={item.dt}>
                  <WeatherCardTitle>
                    {item.dt_txt.slice(0, 10)}
                    <img
                      alt={item.weather[0].main}
                      src={`https://openweathermap.org/img/wn/${item.weather[0].icon}.png`}
                    />
                  </WeatherCardTitle>
                  <WeatherCardContent>
                    <div>{item.weather[0].description}</div>
                    <div>{item.main.temp}°C</div>
                  </WeatherCardContent>
                </WeatherCard>
              ))}
            </WeatherCardContainer>
          </>
        ) : (
          <p>๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ค‘</p>
        )}
      </Container>
    </>
  );
}

export default App;

 

 


 

 

 

1. API ํ‚ค ๋ฐœ๊ธ‰๋ฐ›๊ธฐ

์ผ๋‹จ openweathermap์˜ ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐ€์„œ ํšŒ์›๊ฐ€์ž…์„ ํ•ด์•ผํ•œ๋‹ค. (์ด๋ฉ”์ผ ์ธ์ฆ ๋นผ๊ณ ๋Š” ๋ฒˆ๊ฑฐ๋กœ์šด๊ฑฐ ์—†๋‹ค)

์•„๋ฌดํŠผ ํšŒ์›๊ฐ€์ž…์„ ํ•˜๊ณ  ๋ฉ”๋‰ด์—์„œ ๋งˆ์ดํŽ˜์ด์ง€(๋‚ด ์ด๋ฆ„)์„ ํด๋ฆญํ•œ๋‹ค (๋กœ๊ทธ์•„์›ƒ์€ ์™œ ๊ฐ™์ด ํ‘œ์‹œํ•ด๋’€์ง€..)

 

 

 

๋งˆ์ดํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐ€์„œ API keys ํƒญ์„ ๋ˆ„๋ฅด๋ฉด ๊ธฐ๋ณธ์œผ๋กœ ์ฃผ๋Š” API key๊ฐ€ ์žˆ๋‹ค.

๊ฐ€๋ ค๋‘” ๋ถ€๋ถ„์€ ๋‚ด ๊ฐœ์ธ ๋ฐœ๊ธ‰ํ‚ค๋ผ์„œ ๊ฐ€๋ ค๋’€๊ณ , ๊ฐ์ž ๋ณธ์ธ์˜ ํ‚ค๋ฅผ ๋ณต์‚ฌํ•ด๋‘๋ฉด ๋œ๋‹ค.

 

 

 

1) .env ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ด€๋ฆฌํ•˜๊ธฐ

 

DB ์—ฐ๊ฒฐ์‹œ ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋‚˜ ํฌํŠธ๋ฒˆํ˜ธ, ํ˜น์€ ์ด๋Ÿฐ API์˜ key๊ฐ’๊ฐ™์€ ์ค‘์š”ํ•œ ์ •๋ณด๋“ค์€ .envํŒŒ์ผ (ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ)์— ์ž‘์„ฑํ•ด๋‘๋ฉด ํ•˜๋“œ์ฝ”๋”ฉ ์—†์ด๋„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

.env

  • ํ”„๋กœ์ ํŠธ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์— ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ 
  • ํŒŒ์ผ๋ช…์„ ๊ทธ๋ƒฅ .env ๋กœ ์ง€์–ด์•ผํ•จ (setting.env ์ด๋Ÿฐ๊ฑฐ ์ ˆ ๋Œ€ ์•ˆ๋จ ๋ฌด์กฐ๊ฑด .env)
  • ๋ณ€์ˆ˜๋ช…, ๊ฐ’ ์‚ฌ์ด์— ๊ณต๋ฐฑ์ด๋‚˜ ๋”ฐ์˜ดํ‘œ ๋“ฑ์ด ์กด์žฌํ•˜๋ฉด ์•ˆ๋จ
  • Vite๋กœ ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋ณ€์ˆ˜๋ช…์˜ ์ ‘๋‘์‚ฌ๊ฐ€ ๋ฐ˜๋“œ์‹œ VITE_๋กœ ์‹œ์ž‘๋˜์–ด์•ผํ•จ(CRA๋Š” REACT_APP_๋กœ)
  • github์— pushํ•  ์˜ˆ์ •์ด๋ผ๋ฉด .gitignore ํŒŒ์ผ์— .env๋ฅผ ๋ฐ˜๋“œ์‹œ ์ถ”๊ฐ€ํ•  ๊ฒƒ. (์• ์ดˆ์— ์ˆจ๊ธฐ๋ ค๊ณ  ์ž‘์„ฑํ•œ๊ฑด๋ฐ .env๊ฐ€ ๊ฐ™์ด ์˜ฌ๋ผ๊ฐ€๋ฉด ๊ทธ๋ƒฅ ํŒŒ์ผ ํ•˜๋‚˜ ๋” ๋งŒ๋“  ์‚ฌ๋žŒ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค...)
// VITE๋กœ ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ
VITE_WEATHER_API_KEY=abcdefghijklmnop
// CRA๋กœ ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ
REACT_APP_WEATHER_API_KEY=abcdefghijklmnop

 

 

๊ทธ๋ ‡๊ฒŒ ๋งŒ๋“  ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‚˜๋Š” vite๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— CRA ๋ฒ„์ „์€ ์ฃผ์„์ฒ˜๋ฆฌ,,

 

 

// Vite ํ”„๋กœ์ ํŠธ์ผ ๋•Œ
const API_KEY = import.meta.env.VITE_WEATHER_API_KEY;

// CRA ํ”„๋กœ์ ํŠธ์ผ ๋•Œ
// const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;

 

 


 

 

2.  ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ 

function App() {
  const [weather, setWeather] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // ์œ„์น˜ ์ •๋ณด ์š”์ฒญ
    navigator.geolocation.getCurrentPosition(
    // position <- GeolocationPosition ํƒ€์ž…์˜ ๊ฐ์ฒด
      (position) => {
        // ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฌธ๋ฒ•
        const { latitude, longitude } = position.coords
        
        // ์ƒ๋žต......
        
        },
      (err) => {
      // ์‹คํŒจ ์‹œ ์ „๋‹ฌ๋ฐ›์€ ์—๋Ÿฌ๊ฐ์ฒด์˜ ๋ฉ”์‹œ์ง€๋ฅผ setError๋กœ ์„ค์ •ํ•ด์คŒ
        setError(err.message);
      },
    );
  }, []); // ๋งˆ์šดํŠธ ์‹œ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰

 

Geolocation API

์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉ์ž์˜ ๋™์˜ ํ•˜์— ์œ„์น˜ ์ •๋ณด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” API๋กœ, ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

๋น„๋™๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, HTTPS ํ™˜๊ฒฝ์—์„œ๋งŒ ์ž‘๋™ํ•œ๋‹ค.

 

 

navigator.geolocation

 

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜๋Š” Geolocation ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์†์„ฑ์œผ๋กœ, geolocation์ด ์กด์žฌํ•  ๊ฒฝ์šฐ ์œ„์น˜ ์ •๋ณด๊ฐ€ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•จ

 

  • navigator → ๋ธŒ๋ผ์šฐ์ €์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด์€ ์ „์—ญ ๊ฐ์ฒด (navigator.userAgent, navigator.language, navigator.onLine ๋“ฑ)
  • geolocation → ์œ„์น˜๋ฅผ ๋‹ค๋ฃจ๋Š” ์„œ๋ธŒ ๊ฐ์ฒด
  • (์ž์„ธํ•œ ์ •๋ณด๋Š” MDN ์—์„œ)

 

getCurrentPosition()

 

์žฅ์น˜์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ๋Š” (success, error, options)๊ฐ€ ์žˆ๋‹ค. options๋Š” ์„ ํƒ๊ฐ’์ด๋ผ ํšŒ์ƒ‰์œผ๋กœ (์‚ฌ์‹ค error๋„ ์„ ํƒ๊ฐ’์ด์ง€๋งŒ ๋ณดํ†ต ๊ฐ™์ด ์ฒ˜๋ฆฌํ•˜๋‹ˆ๊นŒ..)

  • success : GeolocationPosition ๊ฐ์ฒด๋ฅผ ์œ ์ผํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜
  • error : GeolocationPositionError ๊ฐ์ฒด๋ฅผ ์œ ์ผํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜

 

position ๋‚ด์—๋Š” coords ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์žˆ๋Š”๋ฐ ์ด ์•ˆ์— latitude์™€ longitude ๊ฐ’์ด ๋“ค์–ด์žˆ๋‹ค.

์ด๋ฅผ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด ํ•œ์ค„๋กœ ์ถ•์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

const latitude = coords.latitude;
const longitude = coords.longitude;
// =
// latitude๋ž‘ longitude๋ผ๋Š” ์†์„ฑ ์ด๋ฆ„์„ ์ •ํ™•ํžˆ ์ผ์น˜์‹œ์ผœ์„œ ๊บผ๋‚ด์˜ด (๊ฐ™์€ ์ด๋ฆ„์˜ ๋ณ€์ˆ˜๋กœ ๋ณต์‚ฌํ•˜๋Š”๊ฒƒ)
const { latitude, longitude } = coords;

 

 


 

 

3. ๋‚ ์”จ ๋ฐ์ดํ„ฐ ์š”์ฒญ

 

์œ„์น˜๋ฅผ ๋ฐ›์•„์™”๋‹ค๋Š” ์ „์ œ ํ•˜์— ๋‚ ์”จ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‚ ์”จ ๋ฐ์ดํ„ฐ๋Š” ์œ„์น˜๋ฐ์ดํ„ฐ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ›์•„์™”์„ ๋•Œ ์ด๋ฃจ์–ด์ง„๋‹ค.

 

  (position) => {
    const { latitude, longitude } = position.coords;
    const API_KEY = import.meta.env.VITE_WEATHER_API_KEY;

    // fetch ํ˜ธ์ถœ
    fetch(
      `https://api.openweathermap.org/data/2.5/forecast?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric&lang=kr`,
    )
      // 
      .then((res) => {
        if (!res.ok) { // res์˜ ์ƒํƒœ๊ฐ€ ok๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด
          // ๋ฐ”๋กœ ์ฒซ๋ฒˆ์งธ catch ๋ธ”๋ก์œผ๋กœ ์ „๋‹ฌ๋จ
          throw new Error('๋‚ ์”จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.');
        }
        return res.json(); // ์„ฑ๊ณต์‹œ json ํŒŒ์‹ฑ ๊ฐ์ฒด ๋ฐ˜ํ™˜
      })
      .then((data) => {
        // 3์‹œ๊ฐ„ ๊ฐ„๊ฒฉ ๋ฐ์ดํ„ฐ ์ค‘์—์„œ ๋งค์ผ 12:00:00 ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋ง
        const dailyForecast = data.list.filter((item) =>
          item.dt_txt.includes('12:00:00'),
        );

        // ์›๋ณธ ๋ฐ์ดํ„ฐ์— list๋ฅผ ๋Œ€์ฒดํ•ด์„œ ์ €์žฅ
        setWeather({ ...data, list: dailyForecast });
      })
      .catch((err) => {
        setError(err.message);
      });
  },

 

 

API ํ˜ธ์ถœ ์‹œ ํ•„์š”ํ•œ ๊ฐ’ (๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ณต์‹ ์‚ฌ์ดํŠธ ์ฐธ๊ณ )

๋งค๊ฐœ๋ณ€์ˆ˜ ์ œ๊ณต ํ•ด์•ผ ํ•  ๊ฐ’ (value)
lat ์œ„๋„ ์œ„์น˜
lon ๊ฒฝ๋„ ์œ„์น˜
appid ๊ณ ์œ  API ํ‚ค
lang ๋งค๊ฐœ๋ณ€์ˆ˜ lang์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์–ธ์–ด๋กœ ์ถœ๋ ฅ์„ ์–ป์„ ์ˆ˜ ์žˆ์Œ (๊ธฐ๋ณธ๊ฐ’ ์˜์–ด)
ํ•œ๊ตญ์–ด : kr
unit ํ™”์”จ ์˜จ๋„ units=imperial
์„ญ์”จ ์˜จ๋„ units=metric (์„ญ์”จ ์˜จ๋„ ์‚ฌ์šฉํ• ๊ฑฐ์ž„!)

 

 

๋ฐ›์•„์˜จ api์˜ ๊ฐ ๋ฐ์ดํ„ฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

์ผ๋‹จ 5์ผ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€์•ผํ•˜๋Š”๋ฐ ๋ฐ›์•„์˜ค๋Š” ์‹œ๊ฐ„ ๊ธฐ์ค€์„ ์ •์˜ค (12:00)๋กœ ์žก์•˜์œผ๋ฏ€๋กœ date๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์†์„ฑ์ธ dt_txt์—์„œ 12:00:00์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋งŒ ํ•„ํ„ฐ๋งํ–ˆ๋‹ค.

์ด์ œ ์•„๋ž˜ ์†์„ฑ์œผ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์™€ ๋ธŒ๋ผ์šฐ์ €์— ๊ทธ๋ ค์ค˜์•ผ ํ•œ๋‹ค.

 

{
  "cod": "200",
  "message": 0,
  "cnt": 40,
  "list": [
    {
      "dt": 1745334000,
      "main": {
        "temp": 13.48,
        "feels_like": 12.35,
        "temp_min": 13.48,
        "temp_max": 13.48,
        "pressure": 1009,
        "sea_level": 1009,
        "grnd_level": 992,
        "humidity": 56,
        "temp_kf": 0
      },
      "weather": [
        {
          "id": 801,
          "main": "Clouds",
          "description": "์•ฝ๊ฐ„์˜ ๊ตฌ๋ฆ„์ด ๋‚€ ํ•˜๋Š˜",
          "icon": "02n"
        }
      ],
      "clouds": {
        "all": 18
      },
      "wind": {
        "speed": 1.11,
        "deg": 266,
        "gust": 1.34
      },
      "visibility": 10000,
      "pop": 0,
      "sys": {
        "pod": "n"
      },
      "dt_txt": "2025-04-22 15:00:00"
    }
  ],
  "city": {
    "id": '์šฐ๋ฆฌ ๋™๋„ค๋ผ์„œ ์ƒ๋žต..',
    "name": "์šฐ๋ฆฌ ๋™๋„ค๋ผ์„œ ์ƒ๋žต..",
    "coord": {
      "lat": "์šฐ๋ฆฌ ๋™๋„ค๋ผ์„œ ์ƒ๋žต..",
      "lon": "์šฐ๋ฆฌ ๋™๋„ค๋ผ์„œ ์ƒ๋žต.."
    },
    "country": "KR",
    // ์ƒ๋žต
  }
}

 

 


 

 

4. ๋ธŒ๋ผ์šฐ์ €์— ํ‘œ์‹œ

์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ณต์‹์‚ฌ์ดํŠธ์˜ ํ•ด๋‹น ๋ถ€๋ถ„์„ ์ฐธ๊ณ 

weather์— ๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ (์ž˜ ๋ฐ›์•„์™”์„ ๊ฒฝ์šฐ) ๊ฐ’์„ ๋ฟŒ๋ ค์ฃผ๊ณ  ์žˆ๊ณ  ๊ทธ๊ฒŒ ์•„๋‹ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ค‘์˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

// ๋งŒ์•ฝ error๊ฐ€ null์ด ์•„๋‹ˆ๋ผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋งŒ ํ™”๋ฉด์— ๋ Œ๋”๋ง
  if (error) return <p>{error}</p>;

  return (
    <>
      <GlobalStyle />
      <Container>
        {weather ? (
          <>
            <Title>{weather.city.name} - 5Days Weather</Title>
            <WeatherCardContainer>
              {weather.list.map((item) => (
                <WeatherCard key={item.dt}>
                  <WeatherCardTitle>
                    {item.dt_txt.slice(0, 10)}
                    <img
                      alt={item.weather[0].main}
                      src={`https://openweathermap.org/img/wn/${item.weather[0].icon}.png`}
                    />
                  </WeatherCardTitle>
                  <WeatherCardContent>
                    <div>{item.weather[0].description}</div>
                    <div>{item.main.temp}°C</div>
                  </WeatherCardContent>
                </WeatherCard>
              ))}
            </WeatherCardContainer>
          </>
        ) : (
          <p>๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ค‘</p>
        )}
      </Container>
    </>
  );
}

 

 

 

๊ฒฐ๊ณผ ํ™”๋ฉด

 

 

 

 

 

์ฐธ๊ณ 
.env ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ : http://rominlamp.tistory.com/22
https://velog.io/@hoho_0815/env-%ED%8C%8C%EC%9D%BC%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC
https://ko.vite.dev/guide/env-and-mode
์œ„์น˜ ๋ฐ›์•„์˜ค๊ธฐ : https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-Geolocation-API%EB%A1%9C-%F0%9F%97%BA%EF%B8%8F-%EC%9C%84%EB%8F%84-%EA%B2%BD%EB%8F%84-%EC%96%BB%EA%B3%A0-%E2%9B%85-%EB%82%A0%EC%94%A8-%EC%98%A8%EB%8F%84-%EC%A0%95%EB%B3%B4%EB%A5%BC-%EC%96%BB%EC%96%B4%EC%98%A4%EA%B8%B0
openweathermap API ์‚ฌ์šฉํ•˜๊ธฐ : 
https://jisilver-k.tistory.com/71