reactdersleri / weather_app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

API: https://openweathermap.org/api

Bu adresteki sign up linkine tıklayarak üye olun.

Üye olduktan sonra e-mail adresinize gelen onaylama butonuna tıklayın.

Ardından https://home.openweathermap.org/api_keys adresine giderek API Key'inizi kopyalayın ve unutmayacağınız bir yere kaydedin. Bu Key sayesinde bu ücretsiz API üzerinden hava durumu verilerini çekebileceksiniz.

Projenizin için bir klasör oluşturun ve bu klasör içinde React projenizi oluşturun.

npx create-react-app .

Sondaki nokta bulunduğunuz klasör içinde projenizi kurmak için gereklidir. Bu komutu kullandığınız klasör boş olmalıdır.

Projenizin ana dizininde .env isimli bir dosya oluşturun ve Key'inizi bu dosya içinde REACT_APP_WEATHER_API_KEY olarak kaydedin.

REACT_APP_WEATHER_API_KEY=api_keyiniz_buraya

Create-React-App ile oluşturulan React projelerinde environment variable kullandığınızda REACT_APP_ ön ekiyle başlatmanız gerekir.

Oluşturduğunuz .env dosyasını .gitignore dosyanıza eklemeyi unutmayın.

Şimdi src klasörü içindeki bütün dosyaları silin ve iki adet dosya oluşturun: App.js ve index.js.

App.js

const App = () => {
  return (
    <div>
      <h2>Hava Durumu</h2>
    </div>
  );
};

export default App;

index.js

import { render } from "react-dom";
import App from "./App";

const root = document.querySelector("#root");

render(<App />, root);

Uygulamamızı en basit haliyle çalışır hale getirdik. Şimdi terminalden uygulamamızı başlatalım.

npm start

Şimdi kullanacağımız API Endpoint'i bulalım.

https://openweathermap.org/current adresine gidin ve By geographic coordinates bölümündeki örnek linki kopyalayın.

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

Bu link içine üç tane parametre gireceğiz: Enlem (lat), Boylam (lon), ve API Key.

Önce API isteğini yapacak olan paketimizi yükleyelim.

npm install axios

Aldığınız değeri tutmak için App fonksiyonu içinde bir state parçası oluşturalım.

const [weather, setWeather] = useState();

Şimdi debu API isteğini yapacak getWeatherData isimli bir fonksiyon oluşturalım. Bu fonksiyonumuz lat ve lon değerlerini parametre olarak alacak ve API Key değerini Environment Variables olarak belirlediğimiz değerden alacak. Veriyi başarılı bir şekilde aldığında ise az önce oluşturduğumuz state parçası içine kaydedecek.

const getWeatherData = async (lat, lon) => {
  const apiKey = process.env.REACT_APP_WEATHER_API_KEY;

  try {
    const { data } = await axios.get(
      `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}`
    );
    setWeather(data);
  } catch {
    alert("Hava durumu verileri alınamadı.");
  }
};

Şimdi kullanıcının giriş yaptığı IP adresine göre enlem ve boylam değerlerini alalım.

Bunun için JavaScript'in GeoLocation özelliğinden faydalanmamız gerekir. Bu işlem için kullanıcının bizim uygulamamıza lokasyon bilgilerine erişmek için izin vermesi gerekecek. Siz bu bilgiye erişmek isteyen bir kod yazdığınızda tarayıcı bunu kullanıcıya otomatik olarak soracaktır. Biz de bu izin geldikten sonra bu bilgileri kullanarak hava durumu verilerini alma işlemini gerçekleştireceğiz.

Normalde bu enlem ve boylam değerlerine ulaşmak için kodumuzu sıfırdan JavaScript ile yazabiliriz. Ancak React ile proje geliştirirken bu tür native JavaScript özelliklerinin hazır bir paket haline getirilmiş versiyonlarını kullanırsanız uygulama geliştirme hızınız artacaktır. Eğer bu işlemin sıfırdan nasıl yapıldığını öğrenmek istiyorsanız, şu adresteki makaleyi inceleyebilirsiniz.

Bu makalede GeoLocation API basit bir hook haline getirilmiştir. Siz bunu isterseniz kendinize bir utility function olarak da hazırlayabilirsiniz.

Şimdi bu paketi yükleyelim ve kullanıcımızın lokasyon bilgilerine ulaşmaya çalışalım.

npm i use-position

App.js

const { latitude, longitude } = useLocation();

console.log({ latitude, longitude });

Bu kodu kaydedip uygulamanızın olduğu pencereyi yenilediğinizde tarayıcının size "Bu site lokasyon bilgilerinize erişmek istiyor" gibi bir mesajla karşılaşacaksınız. Kullanıcı bu izni vermediği sürece latitude ve longitude değerleri undefined olarak konsolda görünecektir. Biz de bu değerler undefined olduğu sürece API isteğimizi yapmayacağız ve kullanıcımıza bu isteğe olumlu cevap vermesi yönünde bir mesaj göstereceğiz.

{
  latitude && longitude ? (
    "hava durumu verileri buraya"
  ) : (
    <>
      Hava Durumu verilerine ulaşabilmek için lokasyon bilgilerinize erişim izni
      vermeniz gerekir.
    </>
  );
}

Basit bir conditional rendering yaparak bu değerlerden birisi falsy olduğu sürece ekranda bir uyarı mesajı gösterdik ve bu değerlerin var olduğu durumda ise ekrana hava durumu verileri buraya şeklinde bir metin yazdırdık. Şimdi de bu verilerin geleceği kısıma gelecek bileşenimizi hazırlayalım.

src klasörü altında components isimli bir klasör oluşturalım ve bu klasörün içinde HavaDurumu.js ismiyle bir bileşen oluşturalım.

HavaDurumu.js

const HavaDurumu = (props) => {
  return "Hava Durumu Verileri Buraya";
};

Şimdi App.js içindeki gerekli yere bu bileşenimizi yerleştirelim.

{
  latitude && longitude ? (
    <HavaDurumu data={weather} />
  ) : (
    <>
      Hava Durumu verilerine ulaşabilmek için lokasyon bilgilerinize erişim izni
      vermeniz gerekir.
    </>
  );
}

Bu aşamada kullanıcı izin verdiğinde ve API'dan veriler geldiğinde bu veriler HavaDurumu bileşenine prop'lar aracılığıyla iletilecektir.

Şimdi HavaDurumu bileşenimizde bu verileri kullanmadan önce, App.js içerisinde useEffect kullanarak latitude ve longitude değerleri truthy olduğunda API isteğimizi gerçekleştirelim.

useEffect(() => {
  latitude && longitude && getWeatherData(latitude, longitude);
}, [latitude, longitude]);

Artık kullanıcımız izin verdiği anda API isteğimiz gerçekleşecek ve HavaDurumu bileşenimize hava durumu verileri prop'lar aracılığıyla gönderilecektir. Biz de bu bileşenimizin içinde props.weather değerinden bu verilere ulaşabileceğiz.

Bu veriyi konsola yazdırdığınızda şuna benzer bir veriyle karşılaşacaksınız.

{
    "coord": {
        "lon": -118.4268,
        "lat": 34.0132
    },
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01n"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 289.24,
        "feels_like": 289.05,
        "temp_min": 288.71,
        "temp_max": 291.15,
        "pressure": 1016,
        "humidity": 82
    },
    "visibility": 10000,
    "wind": {
        "speed": 1.54,
        "deg": 190
    },
    "clouds": {
        "all": 1
    },
    "dt": 1619846583,
    "sys": {
        "type": 1,
        "id": 5872,
        "country": "US",
        "sunrise": 1619787904,
        "sunset": 1619836589
    },
    "timezone": -25200,
    "id": 5341114,
    "name": "Culver City",
    "cod": 200
}

Verilerin detaylı açıklaması için şu adresteki Fields in API response başlığına göz atabilirsiniz.

Şu an için bizim ihtiyacımız olan değerler şunlar:

weather; // Hava durumu (dizi) { id, main, description, icon }
main.temp; // Sıcaklık değeri
dt; // Saniye cinsinden isteğin yapıldığı tarih
name; // Şehir/lokasyon ismi

Şimdi HavaDurumu bileşeni içerisinde bu değerleri ekrana yazdıralım.

const HavaDurumu = (props) => {
  const { weather } = props;

  return (
    <div>
      <h3>{weather.name}</h3>
      <h5>{weather.weather.map((el) => el.description).join(", ")}</h5>
      <p>Sıcaklık: {weather.main.temp}</p>
      <p>Tarih: {new Date(weather.dt * 1000).toLocaleDateString()}</p>
    </div>
  );
};

HavaDurumu bileşenini bu şekilde kaydettiğimizde hata alacağız:

TypeError: Cannot read property 'name' of undefined

Bunun sebebi, uygulamamız ilk yüklendiğinde bu verilerin henüz API'dan alınmamış olması. Bu yüzden, buradaki return ifadesini, prop'dan gelen weather değeri truthy olması şartıyla göstereceğiz. Aksi takdirde verilerin yüklendiğine dair ya da henüz verinin alınmadığına dair dilediğiniz gibi bir şey gösterebilirsiniz. Ben Yükleniyor... şeklinde bir metin göstermek istiyorum.

const HavaDurumu = (props) => {
  const { weather } = props;

  if (weather) {
    return (
      <div>
        <h3>{weather.name}</h3>
        <h5>{weather.weather.map((el) => el.description).join(", ")}</h5>
        <p>Sıcaklık: {weather.main.temp}</p>
        <p>Tarih: {new Date(weather.dt * 1000).toLocaleDateString()}</p>
      </div>
    );
  }

  return "Yükleniyor...";
};

Bu noktada yaptığımız API isteğinde düzeltmemiz gereken iki yer var:

Birincisi, uygulamamızın dili varsayılan olarak ingilizce çünkü biz API isteğini yaparken herhangi bir dil seçeneği belirtmedik. Kullanıcının kullandığı tarayıcıdan dilini öğrenip bunu API isteğimize eklememiz gerekecek.

İkincisi, sıcaklık değeri varsayılan olarak Kelvin birimine göre ayarlanmış. Bizim bunu metrik sistemdeki birime, yani Celsius'a çevirmemiz gerekecek.

Kullanıcının dil seçeneğini tarayıcıdan okumak için getWeatherData fonksiyonu içinde şu değişiklikleri yapalım:

const getWeatherData = async (lat, lon) => {
  const apiKey = process.env.REACT_APP_WEATHER_API_KEY;
  const lang = navigator.language.split("-")[0];

  try {
    const { data } = await axios.get(
      `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&lang=${lang}&units=metric`
    );
    setWeather(data);
  } catch {
    alert("Hava durumu verileri alınamadı.");
  }
};

lang değerini kullanıcının tarayıcısından navigator.language değeriyle okuduk. Bu değer bize en-EN şeklinde bir değer verdi. Bize bu değerin tire (-) işaretine kadar olan kısmı lazımdı. Bu yüzden bu string üzerinde split fonksiyonunu kullandık ve tire olan yerlerden metni böldük. Gelen diziden de ilk eleman olan sıfırıncı elemanı lang değerine atadık.

Bir de axios.get metodu içerisine girdiğimiz linke units=metric değerini ekledik.

Uygulamamızı şimdi yenilediğimizde dilin tarayıcınızın diliyle aynı olduğunu ve sıcaklık değerinin düzeldiğini göreceksiniz.

HavaDurumu bileşeni üzerinde istediğiniz biçimlendirmeyi yapabilir, gelen veri içinden başka değerleri de okuyarak bu bileşeni daha güzel bir hale getirebilirsiniz.

About


Languages

Language:HTML 53.4%Language:JavaScript 46.6%