MERN Full-Stack Tutorial 2020 — Part 3 (connect frontend & backend)
- Part 1: Backend (Server-side)
- Part 2: Frontend (Client-side)
- Part 3: Connecting both piece together
- Part 4: Deployment
Source Code — https://github.com/JinKim7/mern-weather-app
Concurrently Run Frontend and Backend
Within the server app, we need to add more scripts in package.json
so we can run both the frontend and backend at the same time.
In the scripts
property, we should only have the start
command.
Add in these additional commands (server, client, and dev commands):
"scripts": {
"start": "node server/server.js",
"server": "nodemon server/server.js",
"client": "cd client && npm run start",
"dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\""
},
npm run server
— this command usesnodemon
instead of nativenode
to start the server. Improves the dev experience since your app will auto-restart any time there is a change in any of the files.npm run client
— instead of going intocd client
manually and doingnpm run start
every time to run the client, this script will help you just stay in one location of your app to run either client or server or both.npm run dev
— this will run both client and server at the same time, concurrently.
After adding these commands, run this in your root directory of your app (not inside /client
)
npm run dev
This should open a new tab that leads you to your client at localhost:3000
To check your server is working correctly, go to localhost:5000/api/weather
Sweet! We now confirmed that both frontend and backend are running concurrently.
Create a Proxy for Localhost
As of right now, we can’t call the backend endpoints from our frontend. Ideally, on our localhost:3000
client app, we would be able to call our localhost:5000
server app to get weather data. However, it doesn’t work that way out of the box and we will need to proxy our server to call our weather apis (learn more about proxying here).
This will allow our frontend app (client) to call our backend apis (server).
In your /client/package.json
file, add
"proxy": "http://localhost:5000/"
- this will enable us to call the backend server from our client
Calling Our Server from Client and Save To LocalStorage
The first endpoint we will call is the /api/weather
endpoint. This is called when we submit the form to save the zipcode and temp metric.
After the endpoint is called, the form will then save the current weather data at the moment we clicked “save” to our local storage as the property CurrentWeatherData
Don’t just copy/pasta this code directly. There are comments and ellipsis to shorten/ignore the code that should already be in your file. The code you see should mostly be new changes/additions to your current code.
Changes that were made in WeatherForm.jsx
:
import axios from ‘axios';
— to use it to make api callscomponentDidMount
— this will be triggered anytime the component mounts onto the page (i.e. refreshing the page — more info here)refreshSavedWeather
— every time the component mounts, we will call therefreshSavedWeather
function which will call our endpoint to get the weather data based on ourzipCode
and temp metric choice (°C or °F)…and then save it within local storage withCurrentWeatherData
as the key.saveFormData
— generic function to save form data and currently saves to local storagesaveToLocalStorage
— to save the zipcode, temp metric, and current weather data to local storage<Form onSubmit={this.saveToLocalStorage}>
— when we submit the formonSubmit
, it will trigger the functionthis.saveToLocalStorage
to save the info in the form
Let’s test it out.
Try running the app (npm run dev
) and saving a zipcode w/ your choice of temp metric.
To look a look at your local storage to make sure it worked:
- right-click on the app and click
Inspect
(Ctrl+Shift+I or F12) - click the
Application
tab at the top and then click onLocal Storage
under theStorage
section — you should see your localhost url (http://localhost:3000).
Depending on your use-case, you can use localStorage to store data that you don’t really need in your database, like mongo.
I chose to add the localStorage aspect in this app bc if I deploy this app, I don’t need to deploy this app w/ the mongo connection and have any risk of security issues. However, I added the mongo aspect to make it a true “MERN” app.
Checkpoint #8 — https://github.com/JinKim7/mern-weather-app/tree/8.save-to-localstorage
Files Changes — https://github.com/JinKim7/mern-weather-app/pull/9/files
Save to Mongo instead of Local Storage
Changes that were made in WeatherForm.jsx
:
saveToMongo
— to have an option to save to our mongodb in addition, or replacement, of the local storage saving.- Call the
saveToMongo
method insaveFormData
in line 24— if you just want to just use mongodb to save/get data, then you can replace all the instances where you’re saving to local storage and the store w/ one instance of using mongo itself.
When you go through the flow of running the app and saving the form again, the weather data should save in your mongo database now instead of local storage.
Checkpoint #9— https://github.com/JinKim7/mern-weather-app/tree/9.save-to-mongo
Files Changes — https://github.com/JinKim7/mern-weather-app/pull/10/files
Redux
This one is going to be a doozy. I will only gloss over general concepts of Redux, but if you want to learn more about it, read about it here.
Redux will be our tool to help us with state management. Basically, any time the state of our web app changes, the entire application will be able to reflect that w/o a page reload.
There are three key components to know with Redux, imo. That would be Actions, Reducers, and the Store.
Creating our redux actions — create a new folder in client/src/actions
an index.js
file to host all our actions:
- The action type that were made are
SAVE_ZIP
,SAVE_WEATHER_DATA
, etc… This will describe the actions that we will be taking place with our app and what kind of information will be within our payload.
Reducers
The reducer will do the work to change the application’s state based on which action was called to the redux store.
Create these reducer files in client/src/reducers
…
history.js
— this will update the weather history list and only keep the top 10 most recent saves.index.js
— accumulates all of the reducers into one file so the components can just import and pick which reducer it wants.temperature.js
— saves the temperature metric state into the store so it can be used in any componentweather.js
— keeps track of the current weather data within the store and pulls from local storage as default.zipCode.js
— saves the zipcode to the store so that the current zipcode save is accessible to all components.
Integrating the Redux Store
Whenever we first created our client app, we installed redux
into our package.json
, so now we will start using it.
Starting out with the index.js
file within client/src
, we will refactor it to include the Redux store and also a chrome extension that’ll help debug anything within the Redux store.
- Download/Install Redux DevTools (redux chrome extension link), which is the chrome extension to help debug/visualize the redux store
After this change, you should able to run your local app (npm run dev
) and be able to see the Redux DevTools helper when you Inspect
the console with the Redux
tab now.
Connect Redux into our Components
Now, half of the components need to be refactored to use the redux store.
The redux store will manage the state/props from now on.
WeatherForm.jsx
— the changes made was removing the statichistory
state, saves the refreshed weather data into props so that the other components can use it, and mainly adding redux boilerplate.WeatherHistoryPanel.jsx
— mostly redux boilerplate additions in this file and replacingthis.state.history
withthis.props.history
so that we use the redux store instead of the stateWeatherInfoPanel.jsx
— added a method to toggle between Celsius and Fahrenheit depending on which metric was chose and replacing each static field with their dynamic counterpart from the redux store of the weather data.
Checkpoint #10 — https://github.com/JinKim7/mern-weather-app/tree/10.redux
Files Changes — https://github.com/JinKim7/mern-weather-app/pull/11/files
Run the app locally (npm run dev
) and this should be near-final product:
Additional Resources
Here are links to further your knowledge on all the tech we used today.