What Is React (ReactJS)?
At first glance, React is a front-end JavaScript library created by Facebook that is used to create user-interfaces (UI). If you’re new to React, or programming, it can seem slightly confusing, but after a few iterations, anyone can catch fire using it. I am going to give you the quick details then show you how easy it is to make something useful.
ReactJS is frontend JavaScript so the code is run on the client (i.e browser). The backend code doesn’t leave the server. When a URL is requested, frontend code leaves the server, and if someone opened up their developer tools, they could see that code. Remember this for later.
View the Best Weather APIs List
When React hits the client, it takes control of the DOM (Document Object Model) and controls what elements are rendered to the webpage. Handling the render process in this way can do wonders for the user experience (UX), but can be complex for developers as they go deeper in the code. Thankfully, React has some pillars of guidance to keep developers on the right track.
One of the important concepts that I kept in my mind when I first started writing with React is that data flows down. It didn’t click right away, but components, the building blocks in React want to be reused and want to respond to data. Either by receiving the data, or passing it along.
Whenever there is an HTML element that displays—or responds—to data there is an opportunity to create a reusable component. I called it HTML, but you may know that React uses JSX. It looks a lot like HTML but it:
- Has self-closing tags
- Can pass customs props
- Coexists with JavaScript, and
- Uses ‘camelCase’ for attributes and event-listeners.
I mentioned components, too. There are class-based components and functional components. More recently, as of React 16.8, Hooks were introduced. Basically, they are functional components that can hold state. Many times, developers would create function components, but down the road, they needed that component to hold state. Hooks didn’t replace class components, they just added another flexible tool to React. Hooks are new, so we are going to be using them in our app.
We are going to combine React, Hooks, props, JSX, and a weather API to build a stylish front-end application.
Connect to the OpenWeatherMap API
Weather APIs
There are many different types of APIs. One of the most common types, and some of the easiest to use, are weather APIs. Weather APIs pair nicely with geolocation APIs and some actually use geolocation behind the scenes. Most give back easy to understand data that can be impressively cheap to access.
Our app is going to make an HTTP call to a weather API to retrieve data whenever a user enters a city into a form. We are going to use conditional logic, styling, spinners, and error handling to improve the user experience as we wait for that HTTP call to return our data. Before we can get started, let’s go over a few prerequisites.
How To Build a Weather App with React
You can view the complete repository on Github for guidance if you run into trouble and for updates as of 2021.
Prerequisites
- You’ll need to have Node >= 8.10 and npm >= 5.6 on your machine.
- You’ll need to have some familiarity with how to open and use a command-line tool.
- Internet connection.
- You’ll need a code editor (I recommend VS Code).
- A browser other than IE. It does not support the way we are going to call the API (fetch).
- I will be using the UNIX bash command-line tool on macOS for installation. However, using a Mac is not required, because this type of command line is not Mac-specific
- RapidAPI account
Getting Started
- Open a new terminal window and navigate to a comfortable directory.
- Run
npx create-react-app weather_app
in the new terminal. The download process will take a few minutes.npx
is a program that we are giving a command tocreate-react-app
is the command that makes a new React projectweather_app
is an argument we are passing to name the project root directory
- Once the download process is done, jump into the project by executing
cd weather_app
. There are a lot of files but don’t worry, I will keep things simple for this tutorial and will focus on the necessary items. - Open your text editor. I am using Visual Studio Code, so I can use the command-line-interface provided by the editor. In the root project directory, I can enter code ..
- Back in the terminal at the root of the project run
npm start
. This starts the development server on our local machine so the project will compile every time we make a change and save. When the project tries to compile in development mode it informs us of any mistakes that we have made in editing. This is very helpful when starting out.After a few moments, a new browser tab will open to the URL http://localhost:3000 and you should see the project.
We now have a React application running on our machine. Before we choose a weather API we are going to clean up a few items.
- Open
/public/index.html
. This is the page that will be given to browsers when our domain is requested. Notice that there is only one HTML file in the whole project. This is why many ReactJS applications are called single-page-apps, or SPAs. - We will only make one change in this file: locate the
title
tag and change the text inside toWeather App,
or anything you would like the title of the page to be. You should see the change reflected in the tab of your browser after you save. - Navigate to
/src/App.js
. You will notice that the content inApp.js
is being rendered in your browser. This file will become a layout container. To start, remove everything inside the header tag and replace it with:... <h1>React Weather App</h1> ...
- Add two new layout elements (
main
andfooter
) underneath the closingheader
tag with your name in place of “yournamehere”.... <main> {/* add weather fetching component */} </main> <footer> Page created by yournamehere </footer> ...
- In
App.css
, inside the App-header class, change the min-height property to 300px and replace the styling inside theApp
class with the below CSS.... display:flex; flex-direction: column; min-height: 100vh; ...
Unfortunately, the various CSS properties and values that I am using are beyond the scope of this article.
- Add the below code to the end of
App.css
to provide more structure to the HTML.... main { flex-grow: 1; text-align: center; padding: 25px; } footer { padding: 2px; min-height: 100px; display: flex; flex-direction: column; justify-content: center; background: #EEEEEE; font-size: small; text-align: center; } header { padding: 25px; } ...
You should start to see the application layout. The page should look similar to mine.
Connect to the OpenWeatherMap API
Choosing a Weather API
Our React weather app needs weather data, so we are going to take a look at RapidAPI’s options:
- Open up the link above.
Each weather API option gives us four important things:- Description of the API
- Popularity on RapidAPI
- Latency
- Reliability
In the image above, I put a red box around the popularity, latency, and reliability indicators. We are going to use Open Weather Map: - Click it. The Open Weather Map API information page (the page you should already be on) gives us more detailed information.On the far left side, we have a list of API endpoints, each giving us different data, and displaying what kind of HTTP request it uses.The middle section gives us more detailed information describing the selected endpoint and the parameters. Parameters are predefined labels for data that we are going to give to the API (i.e city=Seattle).On the right, my personal favorite of the three sections is an interactive help center that shows us code snippets from a variety of different languages, libraries, and sample responses from the endpoints. This will save us a lot of time.Notice the responses we want are in JSON, Javascript Object Notation, which is a logical way to display information using objects and key-value pairs.TIP: the section on the right will respond to changes we make in the middle section. If we change parameters in the middle, the URL on the right should change.
- In the code dropdown at the top of the right section select Javascript (fetch).
Notice at the end of the URL string we see “q=London%252Cuk”. That is a URI encoded string for the ‘q’ parameter. Essentially, URI encoded strings are the URL compatible versions of the same string, but they account for special characters (i.e spaces and commas). Remember that for later. - Select Current Weather Data in the left section. In the middle section, underneath where it says GET Current Weather Data, in the Required Parameters section, change the ‘q’ parameter from ‘London,uk’ to ‘Seattle’.
Now, the end of the URL simply has ‘seattle’, and it looks the same as how we typed it in the parameter input because we did not have any special characters.
This is the code that we are going to copy & paste directly into our app. However, in order for us to test and use this code, we will need to have an account on RapidAPI and a subscription to Open Weather Map. You can quickly set up an account and subscribe to the basic plan, which gives us 100 calls per day (not exceeding 10 calls per minute) for free using the Open Weather Map API. It’s important to track our API calls. - In the top toolbar on RapidAPI select My Apps. We can see our total API calls and total calls per API in the graph at the bottom.
If, at any point, you feel like you are approaching your quota throughout this tutorial (should not be an issue) double-check your limit on the RapidAPI dashboard and do not continue if you are approaching your quota limit.
We are almost ready to add the code snippet to our app but we need to make a file for it first. - In the
src/
directory, make a folder namedcomponents/
. Inside that folder make another folder namedForecast/
, and finally, inside that folder create a fileForecast.js
.This may seem redundant but it is a common practice in React applications to build folder structure in this way. It makes components, and their corresponding CSS and test code, modular. It won’t be the last time we do it.
- Next, add the below javascript code to our new
Forecast.js
file.import React from 'react'; const Forecast = () => { function getForecast() { // weather data fetch function will go here } return ( // JSX code will go here ) } export default Forecast;
This file will use React Hooks, so it’s important that the name of the function is capitalized. We are now ready to add our code snippet and start programming.
Connect to the OpenWeatherMap API
Fetching Data
- Head back over to the Open Weather Map page, copy the fetch code snippet and paste it into the
getForecast
function. Remove all the extra query parameters so just the main city parameter remains. The URL should behttps://community-open-weather-map.p.rapidapi.com/weather?q=seattle
Now, if we had a way to run this function, we would get the real response (not the example response you saw on RapidAPI’s site). However, we need a way to display the response on the webpage. Currently, this component is not a part of our application and it does not have any JSX code. - Remove the comment // JSX code will go here and replace it with:
... <div> <h2>Find Current Weather Conditions</h2> <div> {JSON.stringify(responseObj)} </div> <button onClick={getForecast}>Get Forecast</button> </div> ...
Our component now has a title, a place to display data, and a button that calls the
getForecast
function when clicked, but what are the curly brackets?Using curly brackets in JSX allows us to mix Javascript right in with our HTML-like code (JSX). We are stringifying our response from the Open Weather Map API using built in Javascript code. This has to be done because the data is returned as JSON and React does not render objects.
We don’t have the
responseObj
variable declared, so we will set up theuseState
functionality that is unique to React Hooks. - Change the first line at the top of the page to import
useState
:import React, { useState } from 'react'; ...
- Above the
getForecast
function, but still inside theForecast
function add:... let [responseObj, setResponseObj] = useState({}); ...
We are creating the
responseObj
variable and the function to change theresponseObj
variable by calling theuseState
function.Wrapping the
responseObj
andsetResponseObj
in an array is called destructuring and is commonly used to easily access values inside arrays or objects. We can destructure this function call because we know theuseState
function returns an array with a variable as the first element and a function as the second.We pass the
useState
function the starting value of the variable. We expect the future value to be a JSON object, so we are setting the starting value to an empty object. - Modify our
getForecast
function to convert the response into a JSON object and then assign the response value to theresponseObj
variable in our state. The inner workings of asynchronous programming are beyond the scope of this article, but thethen
function is what happens after we get our data from the API.... .then(response => response.json()) .then(response => { setResponseObj(response) }) ...
- Head back to our
App.js
file to import our new component and add the component inside ourmain
element. TheApp.js
file should look like this:import React from 'react'; import './App.css'; import Forecast from "./components/Forecast/Forecast"; function App() { return ( <div className="App"> <header className="App-header"> <h1>React Weather App</h1> </header> <main> <Forecast /> </main> <footer> Page created by yournamehere </footer> </div> ); } export default App;
- Click the Get Forecast button, you should see our response object. That response is real data that we can now use.
Connect to the OpenWeatherMap API
Displaying Data
We need to pull the information that we want from this object and display it in a meaningful way. To do that we are going to make a functional component named Conditions that will receive the responseObj
from the Forecast component via props.
- Create a new folder in the
components/
folder. Inside of that folder create a directory namedConditions/
and insideConditions/
create theConditions.js
file.The file will look similar to the last, but our function will take a single argument (props). You may have noticed earlier that an empty object was displayed even though there was not any data. We will add a ternary Javascript operator to display the data only when the HTTP response code is 200. - Inspect the
responseObj
we will see that there is a “cod” key that has the value 200. If we did not enter a valid city in the query parameter the code would be 404. If we did not enter any city it would be a 400. Being able to view the example response—or test response—on RapidAPI helps us see how we can access data in the JSON response object without having to continuously call the API. I have already inspected the response and decided that I want the:- current temperature
- name of the city
- description of conditions.
With that information, I can create a sentence that is easy for a user of the site to read.
- The conditions component will have the following code:
import React from 'react'; const Conditions = (props) => { return ( <div> {props.responseObj.cod === 200 ? <div> <p><strong>{props.responseObj.name}</strong></p> <p>It is currently {Math.round(props.responseObj.main.temp)} degrees out with {props.responseObj.weather[0].description}.</p> </div> : null } </div> ) } export default Conditions;
We are accessing data from the
responseObj
that is inside the props object. This is data flowing top-down. However, we have not set up the conditions component to receive that information yet.Back in the Forecast component, let’s import the conditions component and pass it the
responseObj
. - At the top add:
... import Conditions from '../Conditions/Conditions'; ...
- Remove the div element with our JSON.stringify call and add our conditions component underneath the button element.The JSX code, in Forecast.js, should look like that code below:
... <div> <h2>Find Current Weather Conditions</h2> <button onClick={getForecast}>Get Forecast</button> <Conditions responseObj={responseObj} /> </div> ...
Now when we click the Get Forecast button we see clean data, but you will notice some things are missing:
- The temperature is in Kelvin, with no option to choose between different units.
- We are only getting the weather in Seattle, with no option to enter our own city.
We need an input form.
Connect to the OpenWeatherMap API
Add User Input
The form is going to give the user the option to enter a city name and select between Celcius (metric) or Fahrenheit (imperial). The default will be Fahrenheit. The form could be built in a different component but for our weather example, we are going to build it into our Forecast component.
We are going to be adding dynamic values to our URL query string so we will need to hold those values in state so we can add those variables to the query string on submit.
- Add the two new values, using
useState
above our current responseObj declaration.
// Forecast.js ... let [city, setCity] = useState(''); let [unit, setUnit] = useState('imperial'); ...
Notice we are setting the initial unit value to ‘imperial’. This will act as a default.
The city-input will need to be URI encoded before we put it in our URL string. Javascript has a built-in function that takes care of this.
- Below the
useState
declarations, create a new variable that converts the input string. We will use const because we do not want this new value to change.... const uriEncodedCity = encodeURIComponent(city); ...
If we use a template literal (template string) we can dynamically add variables to our URL string.
- To do this, change the quotes to single backticks ( ` ) and place our variables inside brackets with a leading ( $ ).Our new URL string (inside of the fetch call) will look like: `
https://community-open-weather-map.p.rapidapi.com/weather?units=${unit}&q=${uriEncodedCity}
`
Back in the middle section of the Open Weather API dashboard, you can read that the parameter “units” take arguments for how the temperature data should be converted. Depending on what the user selects, we will either pass “imperial” or “metric” to the URL string.Now, there is a dynamic string that is formed to fully access the global weather data. Let’s add the form and inputs to the JSX code, and convert the current button to call the form’s submit function when clicked. - In
Forecast.js
replace the button element with the form below.... <form onSubmit={getForecast}> <input type="text" placeholder="Enter City" maxLength="50" value={city} onChange={(e) => setCity(e.target.value)} /> <label> <input type="radio" name="units" checked={unit === "imperial"} value="imperial" onChange={(e) => setUnit(e.target.value)} /> Fahrenheit </label> <label> <input type="radio" name="units" checked={unit === "metric"} value="metric" onChange={(e) => setUnit(e.target.value)} /> Celcius </label> <button type="submit">Get Forecast</button> </form> ...
We now have an unstyled form that takes user input—but don’t try to use it. If you clicked the Get Forecast button the page would refresh and we would lose our state and information. In order to make sure this doesn’t happen we pass the event object to our
getForecast
function and call thepreventDefault
method on it. - Our get forecast needs the below addition (instead of ‘event’ we will just use ‘e’):
... function getForecast(e) { e.preventDefault(); ...
- If you click the button now, the
getForecast
function gets called from theonSubmit
listener in the form element and users can search for cities.
Notice we are assigning each input a corresponding value from our state and updating that value with the corresponding function using theonChange
event listener. Each change is stored and passed with the ‘e’ (event) argument. We can now get current weather data, in Fahrenheit or Celcius, and display it right on our webpage. We’re getting to the end of our build, but there are still a few items left. Let’s add some modular CSS code to improve the look of our app.
Connect to the OpenWeatherMap API
CSS
React offers an easy way to create modular CSS files. This helps keep our style sheets clean and up-to-date. In the Forecast
/ folder, create the file Forecast.module.css
. In that file, we are going to add styles that can then be imported into Forecast.js
.
- Add the below CSS to the file:
.TextInput { font-size: large; border: 1px solid #EEEEEE; padding: 5px; border-radius: 3px; display: block; margin: 5px auto; } .TextInput:focus { outline: none; border-color: #719ECE; box-shadow: 0 0 10px rgb(50, 100, 153); } .Radio { font-size: small; } .Button { display: block; margin: 10px auto; padding: .5rem; font-size: 1em; background: darkcyan; border-radius: 5px; color: white; cursor: pointer; margin: 5px auto; }
- In the
Forecast.js
file, import these classes at the top of the file with this line:... import classes from './Forecast.module.css'; ...
The selectors that we put in the CSS file can be accessed on the
classes
object. - Add the CSS classes (like we would add any other Javascript) to the JSX code.
- The text input gets the TextInput class
- The button gets the Button class
- The two label elements get the Radio class
... <input type="text" placeholder="Enter City" maxLength="50" className={classes.textInput} ...
... <label className={classes.Radio}> ... <label className={classes.Radio}> ...
... <button className={classes.Button} type="submit">Get Forecast</button> ...
The form should now be stacked, and when we search for a city a nice vertical structure should be present.
When the forecast displays it tends to push the page around. This could be a little irritating to a user and it’s an easy fix for us because we know the forecast is always going to be relatively small.
Let’s add a CSS file, the same way we did with the Forecast component, alongside the Conditions component to make the visuals a little nicer. We will use this file later for a loading spinner and some error styling, too.
- Create
Condtions.module.css
file in theConditions/
directory. Add the CSS class to it:.Wrapper { min-height: 100px; display: flex; flex-direction: column; }
- Import the file and add the class to the outer
div
element.... import classes from './Conditions.module.css' ...
... <div className={classes.Wrapper}> ...
There should be some empty space below the Get Forecast button that we will fill with an error or a loading spinner depending on what’s going on with our function call. Let’s move on to error handling and loading.
Connect to the OpenWeatherMap API
Error Handling and Loading
It could be possible that the weather API does not return a status code of 200. The user may type in the city wrong, they may not type a city at all, or the user may want to know if there request was even sent.
- In order to cover these scenarios let’s add two more variables to our state.
... let [error, setError] = useState(false); let [loading, setLoading] = useState(false); ...
If the user doesn’t enter any characters into the input we do not want to fire off the request.
- Add a check just below our
e.preventDefault()
call for this.... if (city.length === 0) { return setError(true); } ...
This ends the function and sets the error to true which will trigger a message in the Conditions component (we will add soon) and, as we planned, not fire off an empty request.
Although the Javascript built-in
fetch
function has a catch block, it will still run the code in the then block if the API request returns with a status of 400 or 404.We don’t want that. If there is an error, we want to display an error message to the user and not set the response object.
- Add a similar block of code to the then block to check for an error and throw an error if the code on the response is not 200. Inside the second then block of our fetch function add:
... if (response.cod !== 200) { throw new Error() } ...
This will run the code in the catch block, so let’s set the error value to true in the catch block with
setError(true)
.We are almost done with the function but we need to think about how loading will work;
- Loading should be true at the start of the function
- Loading should be false when the function is successful
- Loading should be false if the function fails.
It’s important to give the user feedback when making API calls or any HTTP requests. Some connections are slower than others and servers can get busy.
- Add the above loading logic to our function with a few more clean up items. The finished
getForecast
function will look as follows:function getForecast(e) { e.preventDefault(); if (city.length === 0) { return setError(true); } // Clear state in preparation for new data setError(false); setResponseObj({}); setLoading(true); let uriEncodedCity = encodeURIComponent(city); fetch(`https://community-open-weather-map.p.rapidapi.com/weather?units=${unit}&q=${uriEncodedCity}`, { "method": "GET", "headers": { "x-rapidapi-host": "community-open-weather-map.p.rapidapi.com", "x-rapidapi-key": "apikey" } }) .then(response => response.json()) .then(response => { if (response.cod !== 200) { throw new Error() } setResponseObj(response); setLoading(false); }) .catch(err => { setError(true); setLoading(false); console.log(err.message); }); }
It won’t matter if our logic is correct if there is nothing to display that represents the logic. We are going to use the Conditions component for error and loading feedback.
We’ll need two ternary expressions in the JSX code of the Conditions components that will turn on and off depending on the props that are passed.
- Add these two props to the Conditions component in Forecast.js so it looks like this.
... <Conditions responseObj={responseObj} error={error} //new loading={loading} //new /> ...
- Head over to
Conditions.js
to add the logic.
This time we will use different logical shortcut syntax that looks a little cleaner. We will be directly looking at the error and loading booleans and the component will decide what elements to display. - Add this code at the top of our main div.
... {props.error && <small>Please enter a valid city.</small>} {props.loading && <div>Loading...</div>} ...
If we try to look up a city without entering a name the error message will appear, and while we wait for the response from the API we will see an element informing us that data is loading.
- Let’s make it a little better by adding some styling to
Conditions.module.css
.... .Small { color: red; } /* this code was pulled from https://www.w3schools.com/howto/howto_css_loader.asp */ .Loader { border: 16px solid #f3f3f3; border-top: 16px solid rgb(90, 89, 89); border-radius: 50%; width: 50px; height: 50px; animation: spin 2s linear infinite; margin: 10px auto; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
After importing the class object and adding the corresponding classes to the proper elements the final
Conditions.js
page should look like this:import React from 'react'; import classes from './Conditions.module.css' const conditions = (props) => { return ( <div className={classes.Wrapper}> {props.error && <small className={classes.Small}>Please enter a valid city.</small>} {props.loading && <div className={classes.Loader} />} {props.responseObj.cod === 200 ? <div> <p><strong>{props.responseObj.name}</strong></p> <p>It is currently {Math.round(props.responseObj.main.temp)} degrees out with {props.responseObj.weather[0].description}.</p> </div> : null } </div> ) } export default conditions;
Now, we have error handling and a loader for user feedback. Only two things left;
- Security
- Logo
Connect to the OpenWeatherMap API
Security
If you didn’t already notice, I removed my API-key when I pasted my code in for the getForecast
function. React is a front-end framework, so all of our code gets sent to the client. That would mean our API-key could be viewed by anyone that was able to see our source code if they opened up the developer tools.
If we wanted to create an optimized build of our application we could run npm run build
and all of our code would be made small and bundled for performance. Even if we put the API-key in a .env
file and imported it with process.env.REACT_AP_API_KEY
(this is built-in support for non-sensitive environment variables) our key could still be found.
What that means is this code should not be put on a server, or CDN, to maintain the integrity of our API-key. I can only recommend that you set up a backend Node.js server for our weather app.
What we can prevent is committing our API-key to Github when we share it with version control. This is where the /.env
file is useful.
Notice that when the app was created for us a /.gitignore
file was created automatically at the root of the project directory. Files and folders in this file will not be committed to remote repositories. Explaining version control in depth is outside the scope of this article, so please bear with me.
Inside this file there are a few .env
files.
- .env.local
- .env.development.local
- .env.test.local
- .env.production.local
We are going to create a permanent .env
file named .env
because our API-key is not a test or development key.
- Add
.env
to our.gitignore
file. - Create the .env file at the root of our directory. Inside the file, add the following line:
REACT_APP_API_KEY=yourapikey
It’s important that the variable starts with ‘REACT_APP_’. If it doesn’t it will not be recognized.
- In
Forecast.js
, replace your current API-key withprocess.env.REACT_APP_API_KEY
. The line should like the line below:... "x-rapidapi-key": process.env.REACT_APP_API_KEY ...
- Restart the development server (Ctrl+C in bash and then
npm start
to restart it). - Test app by entering a city name.
The application should still be able to make calls to OpenWeatherMap.
Connect to the OpenWeatherMap API
Logo
This is just a finishing touch. I will only explain where to add the code.
- Create a folder in the components/ directory titled Logo, and inside of that make two files: Logo.js and Logo.module.css.
- Paste the below code into the corresponding files.
// Logo.js import React from 'react'; import classes from "./Logo.module.css" const Logo = () => ( <div className={classes.sky}> <div className={classes.circle}/> <div className={classes.cloud1} /> <div className={classes.cloud2} /> <div className={classes.cloud3} /> </div> ) export default Logo;
/* Logo.module.css */ .circle { width: 60%; height: 60%; background: yellow; border-radius: 50%; margin: auto; } .sky { display: flex; width: 200px; height: 200px; background: skyblue; border-radius: 5px; } .cloud1 { position: absolute; margin-top: 120px; margin-left: 50px; width: 100px; height: 50px; background: rgb(226, 224, 224); border-radius: 80px / 40px; } .cloud2 { position: absolute; margin-top: 100px; margin-left: 5px; width: 100px; height: 50px; background: rgb(226, 224, 224); border-radius: 100px / 50px; } .cloud3 { position: absolute; margin-top: 90px; margin-left: 50px; width: 60px; height: 60px; background: rgb(226, 224, 224); border-radius: 60px; }
- Import the component into App.js:
.... import Logo from './components/Logo/Logo'; ...
- Add the Logo component inside the header element but above the h1 element.
... <header className="App-header"> <Logo /> <h1>React Weather App</h1> </header> ...
- Our app is now is a little easier to look at!
Thank you for following along. I hope you learned something and feel empowered to start building APIs with React!
Connect to the OpenWeatherMap API
What’s Next?
This app has a lot of room to improve. I have a few suggestions below for improving or extending the application.
- As previously mentioned, try to extend or change our weather app example to use backend Node.js code
- Move our weather form into a different component folder and import it into our Forecast component.
- Add a second API endpoint from Open Weather Map, or refactor our current endpoint to display search options.
- Integrate with Google Maps
Jimmy says
I feel like it would have been nice to see larger chunks of code than just the code that needs to be put into each file. The information about where to put the code is way too vague for a beginner. That being said, I still haven’t reached the end of the tutorial. Please put the final code sample at the end of the page so we can understand the flow better. Thanks
Jarrett Retz says
Hey Jimmy,
You are totally right. I have uploaded the code repository to Github and it can be viewed at https://github.com/jdretz/rapid-api-react-weather-app-tutorial. Hope that helps, and thanks for reading!
Jarrett
Tarik says
Hi Jarrett,
Thanks for putting this tutorial together. I just finished and it’s great 🙂
Jarrett Retz says
Thank you Tarik I am glad you found it useful!
Yami says
Great tutorial. I was able to build my weather up in React using your tutorial.
Thanks.
RapidAPI Staff says
Glad we could help Yami!
Nicholas says
Jarrett, thank you for a great tutorial. I am starting to make the connections w api calls and react… however, I’m getting cors errors and wondering if anyone else here has had these issues?
I have tried several things including running a Chrome extension for allowing cors, adding a header field, adding paths, and none of it helped. Wondering if the api cant be called from the front end? If anyone has a fix for this issue, { HELP! } is appreciated.
Nicholas says
the error: Access to fetch at ‘https://community-open-weather-map.p.rapidapi.com/weather?units=imperial&q=Seattle’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
Jarrett Retz says
Hey Nicholas,
I just took a look at the discussions on the API and I did not see anyone else post about the same issue. You can try setting the ‘mode’ fetch option to ‘no-cors’ but the request may still not return anything useful. I would double check your code and try to contact OpenWeatherAPI.
Are you able to test the API from the RapidAPI dashboard?
Matt says
Hey Jarrett,
I am currently on the Fetching Data section and having issues with the data showing up. As far as I can tell, all of my code is as it should be, after reading through the section again and looking at the Forecast.js file on the repository you posted, but when I click on the “Get Forecast” button, nothing shows up. Also, before I press the button, a {} appears above the button, but disappears after I press it. I feel like it has something to do with {JSON.stringify(responseObj)}, but I can’t figure out what the problem is.
Thanks!
Jarrett Retz says
Hey Matt,
Thanks for reading! I would check the Network tab in your Dev Tools to see if your getting back a valid response. If you are getting back a response with data inside, then the error is coming somewhere in between the assignment of the variable and displaying the variable.
The empty brackets is the initial value of responseObj variable. So that should go away after you click the button because a new object will be assigned with the data.
If you continue on to displaying the data, the bug may present itself.
I hope that helps.
Thanks again,
Jarrett
I-Ape says
Hi Jarrett 🙂
what changes would be made so rather than typing in the location, it detects location from the ip?
thanks
Thiebaud says
Hi, great tutorial but i have a problem. I always have an error: “403 forbidden” and i don’t know why, if anyone could help me please 🙂
Dmitry says
Thank you, Jarret – everything works as expected (after catching and debugging typos for few hours).
Good learning experience!
Jarrett Retz says
Hello I-Ape,
You could use the Javascript GeoLocation API to secure the latitude and longitude. Then pass those in to the API call following the Weather API documentation.
You can read more about the Geolocation API on MDN.
https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API
Jarrett Retz says
Hey Thiebaud,
Were you able to resolve the 403 forbidden?
Jarrett Retz says
Hello Dmitry,
Glad you found it useful, sorry to hear about the typos!
Jarrett
Alba says
Hi Jarret, thank you for the walk through. It was very clear and helpful. I am trying to get the data for the 5 day forecast but Im not sure how we get the data from the body of the 5 day forecast. For example for the current weather we use {props.responseObj.wind.speed}. What about the forecast? Thank you.
Ryan says
I am current working on displaying the data and am getting strange temps. I have changed my location and still end up with something around 282 degrees. I tried removing the Math.round and just get 282.15 degrees. Not sure why this is happening, any ideas?
Ryan says
I was a bit ahead of myself! Thank you for this project!
Sim says
@Ryan – I think the temperature you are getting is in Kelvin. It’s easy enough to convert it to Farenheit or Celcius. If you don’t remember the conversion formulae from high school, you can google it pretty easily. 🙂
Sue Holder says
Hi Jarett,
I am having the same issue as reported by Matt and to debug (after several hours of trying and going back and forth), I replaced null in the else condition with No data if I add the JSON.stringify(reponseObj) I get the raw JSON but also ‘No data’, which I can’t figure out why. In dev tools and in the API I am getting the data and I get a response of 200 so I don’t know what to do to resolve this. Is there any advice you could give me?
Sue Holder says
If anyone else is having an issue with displaying the data in the Conditions component:
1. add quotations around the status code. That will then show you have a typeError.
If you examine the responseObj you will see that it doesn’t have a name or main property on the root etc. It does have a list property and name and main are available on the list property.
2. if you add in responseObj.list[0].name and responseObj.list[0].main.temp; responseObj.list[0].weather[0].description then the error will be resolved.
Lee Walton says
I got up to the fetch section however I am new to react and havent been using java for a while now.
For some reason the fetch section will not get the api call no matter what I try.
Massively fustrating that the code for that isnt included.
Jarrett Retz says
Hey Lee,
I’m sorry to hear about your troubles. Here’s a link to the finished repository that you can use for reference. I’ll double-check it to make sure it’s accurate, but it includes the fetch section you’re referring to.
https://github.com/jdretz/rapid-api-react-weather-app-tutorial
Good luck and thanks for reading!
Mario says
I have just begun learning React and this tutorial from you have been very helpful! Hopefully, I can refer to you for assistance with future React apps when the need arise.
Thank you!
Dan Bloch says
Should the spinner under “get forecast” stop spinning once the forecast is loaded? I presume it should, but mine doesn’t.
Any thoughts, anyone?
Dan Bloch says
Another thing: when I update Forecast.js with the line: “x-rapidapi-key”: process.env.REACT_APP_API_KEY, I get the error message: “Please enter a valid city” and no weather data.