Search code examples
javascriptreactjsapiif-statementopenweathermap

How to use the IF statement to avoid the Weather API fetch result crashing once the user types wrong the city name?


Summarizing The Problem

- Details About The Goal

A weather app that renders on the screen the data fetched from OpenWeather API.

- Actual and Expected Results

Whether the user types correctly or not the city name or presses enter in the empty field, no result render on the screen. I would like help to resolve it.

What it Has Been Tried So Far (Update 1.1)

I've placed a conditional operator below the *Search* component in the *App.js* file:

{typeof dataSearch === "undefined" ? (<></>) : ()}
{typeof dataSearch === "undefined" ? (
  <></>
) : (
  <>
    <CurrentWeather resultData={weatherData} />
    <ForecastWeather resultData={forecastData} />
  </>
)}

I would not expect that it would leave the screen blank.

Well, thank you for reading my post.

The Complete Code

- App.js (Update 1.1)
import React, { useState } from "react";
import { Api } from "./Api";
import { Container } from "react-bootstrap";
import {
  Search,
  CurrentWeather,
  ForecastWeather,
  Footer,
} from "./components/index";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";

function App() {
  const [weatherData, setWeatherData] = useState(null);
  const [forecastData, setForecastData] = useState(null);

  const handleSearchLocation = (dataSearch) => {

    const weatherDataFetch = fetch(
      `${Api.url}/weather?q=${dataSearch}&units=metric&appid=${Api.key}`
    );
    const forecastDataFetch = fetch(
      `${Api.url}/forecast?q=${dataSearch}&units=metric&appid=${Api.key}`
    );

    Promise.all([weatherDataFetch, forecastDataFetch]).then(
      async (response) => {
        const weatherResponse = await response[0].json();
        const forecastResponse = await response[1].json();

        setWeatherData(weatherResponse);
        setForecastData(forecastResponse);
      }
    );
  };

  return (      
    <div className="App">
      <div className="contentApp">
        <Container>
          <Search
            searchResultData={handleSearchLocation}
            textPlaceholder="Search for a place..."
          />
          {typeof dataSearch === "undefined" ? (<></>) : (
            <>
          <CurrentWeather resultData={weatherData} />
          <ForecastWeather resultData={forecastData} />
          </>
          )}
          <Footer />
        </Container>
      </div>     
    </div>
  );
}

export default App;

Yippee-ki-yay


Solution

  • Summarizing The Problem

    The main issue that I was facing was with handling the API logic to display the search result on the screen and before that, once the user types wrong the city name or pressed enter into the blank input field, the program crashed.

    However, I've begun to search for why this was happening and in the course of time after observing other codes, I've seen that the IF statement should be used to fix this issue.

    Problem Resolution

    After several attempts, the solution was to remove the Promise.all() and separate them, weather and forecast, into await blocks of codes with their own IF statement:

    // App.js
        await weatherDataFetch
          .then((res) => {
            if (!res.ok) {
              throw new Error("City name: typed wrong or blank input.");
            }
            return res.json();
          })
          .then((res) => {
            setWeatherData(res);
          })
          .catch((err) => {
            console.log(err);
          });
    
        await forecastDataFetch
          .then((res) => {
            if (!res.ok) {
              throw new Error(
                "Weather forecast not found. Waiting for the correct city name."
              );
            }
            return res.json();
          })
          .then((res) => {
            setForecastData(res);
          })
          .catch((err) => {
            console.log(err);
          });
    

    The async has been moved to the top of the handleSearchLocation function:

    // App.js
    const handleSearchLocation = async (dataSearch) => {
    

    And for the last, deleting the old attempt to clean and avoid conflict and crashes:

    // Old
    // App.js
      return (      
        <div className="App">
          <div className="contentApp">
            <Container>
              <Search
                searchResultData={handleSearchLocation}
                textPlaceholder="Search for a place..."
              />
              {typeof dataSearch === "undefined" ? (<></>) : (
                <>
              <CurrentWeather resultData={weatherData} />
              <ForecastWeather resultData={forecastData} />
              </>
              )}
              <Footer />
            </Container>
          </div>     
        </div>
      );
    
    // New
    // App.js
      return (
        <div className="App">
          <div className="contentApp">
            <Container>
              <Search
                searchResultData={handleSearchLocation}
                textPlaceholder="Search for a place..."
              />
              {weatherData && <CurrentWeather resultData={weatherData} />}
              {forecastData && <ForecastWeather resultData={forecastData} />}
              <Footer />
            </Container>
          </div>
        </div>
      );
    
    Note

    Other beginners, like me, observe other codes and especially code variations of the same programs because there are a lot of ways to do the same thing.

    Yippee-ki-yay