Пятница, 26 августа 2022 03:46

Погода API OpenWeatherMap и W3C Geolocation API. ReactJS

Оцените материал
(5 голосов)

Материал посвящен описанию программного кода, результатом выполнения которого - элегантная (Bootstrap 5) таблица, демонстрирующая актуальное для местонахождения пользователя состояние погоды по версии погодного сервиса OpenWeatherMap.

Геотаргетинг определяется автоматически при условии предоставления соответствующего разрешения браузеру (и устройству).

Сходу оговорюсь: коль скоро такого рода приложение крайне несложно и многократно разрабатывалось (на любых языках программирования), сложно говорить о какой-либо эксклюзивности. Тем не менее, те пара-тройка аналогичных примеров, которые внимательно рассмотрел на гитхабе - однозначно не устроили, поэтому кодил самостоятельно. Вполне может статься, профи ReactJS доставит удовольствие попытаться найти те или иные огрехи в предлагаемом решении; ну, что же. Написано было быстро, сугубо в целях знакомства с реактом, и вполне может быть со временем отредактировано.

 

Dev banner 3

 

OK. О некоторых основах работы с create-react-app рассказано в статье Как выглядит сайт на реакте; будем считать, что вы уже создали рабочее приложение.

Понадобится доустановить три пакета:

 

npm install react-bootstrap bootstrap moment

 

Теперь создайте файл .env в корне приложения. Всего две строки:

 

REACT_APP_WEATHER_API_KEY = XXXXXXXXXXXXXXXXXXXX
HTTPS = true

 

Первая строчка определяет константу бесплатного ключа доступа к API OpenWeatherMap, что называется - зарегистрируйтесь и получите. Строчка вторая - optional, не является обязательной. Но - очень рекомендую; позволяет избежать в процессе разработки некоторых проблем, связанных с тем, что современные браузеры при работе с Geolocation API требуют защищенного соединения.

 

Увидеть на гитхабе.

 

Скрипты react-app можно подробно и не торопясь рассмотреть в публичном репозитории автора, здесь же коснемся только лишь ключевого файла App.js. Который вполне способен выглядеть следующим образом:

 

import { useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Table from "react-bootstrap/Table";
import moment from "moment";

const App = () => {
  const [status, setStatus] = useState(null);
  const [apiData, setApiData] = useState({});

  async function fetchData(lat, lon) {
    await fetch(
      `//api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.REACT_APP_WEATHER_API_KEY}&units=metric`
    )
      .then((res) => res.json())
      .then((data) => setApiData(data));
  }

  const getLocation = () => {
    if (!navigator.geolocation) {
      setStatus("Geolocation is not supported by your browser");
    } else {
      setStatus("Locating...");
      navigator.geolocation.getCurrentPosition(
        (position) => {
          setStatus(null);
          fetchData(position.coords.latitude, position.coords.longitude);
        },
        () => {
          setStatus("Unable to retrieve your location");
        }
      );
    }
  };

  const cssStyle = {
    backgroundImage: "url('/background.jpg')",
    height: "100vh",
    backgroundSize: "cover",
    backgroundRepeat: "no-repeat",
  };

  return (
    <div style={cssStyle}>
      <button onClick={getLocation}>
        Get Current Weather for Your Geo-Targeting
      </button>
      <p>{status}</p>
      {apiData?.coord?.lat && (
        <Table bordered striped hover variant="dark" size="sm">
        <caption>{moment.unix(apiData?.dt).format('MMMM Do YYYY, h:mm:ss a')}</caption>
          <tbody>
            <tr>
              <th scope="col" className="align-middle">
                Average Weather
              </th>
              <td>
                <img
                  src={`//openweathermap.org/img/w/${apiData?.weather?.[0].icon}.png`}
                  alt={apiData?.weather?.[0].main}
                />
              </td>
            </tr>
            <tr>
              <th scope="col">Area</th>
              <td>{apiData?.name}</td>
            </tr>
            <tr>
              <th scope="col">Description</th>
              <td>{apiData?.weather?.[0].description}</td>
            </tr>
            <tr>
              <th scope="col">Temperature</th>
              <td>{apiData?.main?.temp} &deg;C</td>
            </tr>
            <tr>
              <th scope="col">Sunrise</th>
              <td>{moment.unix(apiData?.sys?.sunrise).format("hh:mm a")}</td>
            </tr>
          </tbody>
        </Table>
      )}
    </div>
  );
};

export default App;

 

Примечание. Скрипт отображает картинку в качестве бэкграунда, являя собой первую версию приложения. В дальнейшем вместо фонового изображения использован vanta.js; гитхаб демонстрирует оба варианта кодовой базы.

 

Показанный выше код полностью работоспособен; вы можете сменить

const App = () => {
...

на

function App() {
...

, в данном случае это не имеет значения. А вот что действительно рекомендовал бы сделать - это вынести бэкграунд vanta.js в отдельный компонент, так гораздо удобнее:

import React, { Component } from "react";
import FOG from "vanta/dist/vanta.fog.min";
import * as THREE from "three";

class FogComponent extends Component {
  constructor() {
    super();
    this.vantaRef = React.createRef();
  }

  componentDidMount() {
    this.vantaEffect = FOG({
      el: this.vantaRef.current,
      THREE: THREE,
      mouseControls: true,
      touchControls: true,
      gyroControls: false,
      minHeight: 200.0,
      minWidth: 200.0,
      highlightColor: 0xb6a574,
      midtoneColor: 0xf5b3a9,
      lowlightColor: 0xa1016,
      baseColor: 0x537dcd,
      blurFactor: 0.6,
      speed: 5.0,
      zoom: 1.5,
    });
  }
  componentWillUnmount() {
    if (this.vantaEffect) this.vantaEffect.destroy();
  }
  render() {
    const { children } = this.props;
    return (
      <div style={{ height: "100vh", width: "100%" }} ref={this.vantaRef}>
        {this.props.children}
      </div>
    );
  }
}

export default FogComponent;

За подробностями см. гитхаб проекта, также отличную статью How to Pass Properties Object to Child Component.

 

Очень коротко и по верхам: как видите, фетчим данные погоды посредством API call, описанного в документации OpenWeatherMap; этой цели служит async function fetchData(), куда через параметры передаем значения широты и долготы. Функция вызывается из getLocation, назначение которой вполне понятно из названия: да, попросту получаем географические координаты здесь и передаем дальше. В скобках: что касается времени заката и восхода солнца - OpenWeatherMap отдает время unix, для форматирования которого нам и понадобился moment.

А getLocation, в свою очередь, инициируется по нажатию кнопки:

 

<button onClick={getLocation}>
  Get Current Weather for Your Geo-Targeting
</button>

 

Дополнительно объявляем cssStyle;- думаю, не вызывает вопросов (картинка-бэкграунд). Таблица же построена с использованием optional chaining operator (?.) вот по такому принципу:

 

<tr>
    <th scope="col">Description</th>
    <td>{apiData?.weather?.[0].description}</td>
</tr>

 

Что в итоге получилось.

 

Пожалуй, на этом пока все.

Последнее изменениеВторник, 11 октября 2022 08:34

Оставить комментарий

Добавьте ваш комментарий

ReactJS