Today, We are going to look into the Mindset required to create a Complex but Simple Looking Weather App.
Since the Data is availaible via API called WeatherAPI, we are going to use that to request weather data when specific city is typed.
As usual I will not dicuss anything about CSS (except when neccessary) as design is something that has nothing to do with the programming of app. The sky's the limit and you can do any design you want.
After creating a React App with npx create-react-app {app-name}
, we have to think that there are two API's that we will use.
One gives us recommendations when we half-typed a city's name and other displays the weather data of that city when selected.
Let's create a Rough Structure in our Mind
First we create a input where on each change, the changed input is used to fetch reccomendations and displayed. Second, when the reccommended data (CityName) is clicked, the CityName is passed in function which fetches the weather data of that city and displays it.
Now Let's Code this,
We create a Search Bar Component
in which a Input
Element would be present which will call the API again and again when there is a change in the Input
, as this will provide the reccommendations of name a/q to the name of the city typed in input
.
So in Search Bar Component
in App.js
,
const SearchBar = () => {
// we use useContext for better management of states
const {
searchTerm,
setSearchTerm,
recommendation
} = useGlobalContext();
// 1. setSearchTerm will be used to set the term we type in
// input element
// 2. that input value is then displayed in the input element via
// searchTerm,
// 3. the recommendation which will be displayed here is the data
// i.e is received after request with value of searchTerm is made
// 4. Request is done in context.js page where the api is :
// https://api.weatherapi.com/v1/search.json?
// key={Your_Key_Provided_When_You_Create_an_Account}&
// q=${searchTerm}
return (
<div className="searchBar">
<p className="info">
{/* neccessary instructions */}
Search and Select the City, Only then the Weather Data of the
City will be Displayed :
</p>
<input
type="text"
name="search"
// the setSearchTerm is called everytime when there is
// change in input
// making the process of calling the reccommendations via API
// again and again, thus displaying reccommended data a/q
onChange={(e) => setSearchTerm(e.target.value)}
value={searchTerm}
/>
{recommendation.length > 0 && <Recommendations />}
</div>
);
};
Now let's see how the data is requested in context.js
useEffect(() => {
// this runs with each change in searchTerm state
fetchData();
}, [searchTerm]);
const fetchData = async () => {
// now when this runs the data is fetched a/q to the
// input in searchTerm
try {
const res = await fetch(
`https://api.weatherapi.com/v1/search.json?
key=5baa84cbff214636ad162010223006&q=${searchTerm}`
);
const data = await res.json();
if (data.length > 0) {
const cityNameRecommendations = data.map((place) => {
return {
name: place.name,
region: place.region,
country: place.country,
};
});
// data added if present
setRecommendation([...cityNameRecommendations]);
} else {
// if not, empty array is placed to not display anything
setRecommendation([]);
}
} catch (error) {
console.log(error);
}
};
The data is then rendered a/q below the input element in Recommendations Component
const Recommendations = () => {
const {
setRecommendation,
recommendation,
fetchCurrentWeather,
setSearchTerm,
} = useGlobalContext();
// this runs after one of the displayed data
// is clicked, this clears the reccomendations,
// clears the input element,
// and sends the cityName clicked to fetch the
// weather data
const handleClick = (rec) => {
setRecommendation([]);
fetchCurrentWeather(rec);
setSearchTerm("");
};
return (
<div className="recommendations">
{/* the data is displayed */}
{recommendation.map((rec, id) => (
<div
key={id}
// when clicked on it, a function is triggered
// the name is also passed
onClick={() => handleClick(rec.name)}
className="recommendation"
>
{rec.name}, {rec.region}, {rec.country}
</div>
))}
</div>
);
};
Furthermore, we see how the sent cityName data is used to fetch Weather Data
const fetchCurrentWeather = async (cityName) => {
try {
const res = await fetch(
`https://api.weatherapi.com/v1/current.json?
key=5baa84cbff214636ad162010223006&
q=${cityName}&aqi=yes`
);
const data = await res.json();
// the received data is set in currentWeather State
setCurrentWeather([data]);
} catch (error) {
console.log(error);
}
};
Finally, in the DisplayInfo Component
, the data is rendered.
We also add a feature where the AQI Data
Background Color is changed a/q to it's data.
const DisplayInfo = () => {
// we use useRef to access the properties of element
// in which the background color is to be set
const aqi = useRef();
// weather data received is destructured
const { currentWeather } = useGlobalContext();
const [data] = currentWeather;
const { current } = data;
// we use it as short form
const pm10 = current.air_quality.pm10;
// this renders when the weather-data is loaded
useEffect(() => {
// we use it as short form as well
const style = aqi.current.style;
// a/q to the pm10 data, the colors are added
// to give it graphical meaning
if (pm10 <= 50) {
style.backgroundColor = "#d4e6a5";
style.color = "black";
} else if (pm10 > 50 && pm10 <= 100) {
style.backgroundColor = "#e5e6a5";
style.color = "black";
} else if (pm10 > 100 && pm10 <= 150) {
style.backgroundColor = "#e6d5a5";
style.color = "black";
} else {
style.backgroundColor = "#e6a9a5";
style.color = "black";
}
});
return (
<div className="weather">
<div className="current-condition">
<div className="img">
<img src={current.condition.icon} alt="weather-icon" />
</div>
<div className="weather-data">
<p>
<span>Location:</span>
{data.location.name}
</p>
<p>
<span>Weather:</span>
{current.condition.text}
</p>
<p>
<span>Last Updated:</span>
{current.last_updated}
</p>
<p>
<span>Temp (°C):</span>
{current.temp_c}
</p>
</div>
</div>
{/* the aqi useRef is used here to access it's properties */}
<div className="aqi" ref={aqi}>
<p>
<span className="aqi-data">
AirQuality (PM<sup>10</sup>):
</span>
{Math.floor(pm10)}
</p>
</div>
</div>
);
}
Hence, with this we finally create the project after adding designs and we are ready to deploy it to display it on internet.
I hope you understood the thought process that got involved in it. I wrote it as if I was trying to imagine myself on how to create this app in first place.
I hope you enjoyed it, till then Keep Making Apps
P. S - Constructive Criticism Always Welcomed ✌