In the previous part of this tutorial, How to Build a Login/Register App with the MERN Stack (Part 3): Creating API Endpoints, we created our API endpoints using Express. In this part we will create our app’s Frontend Routes using React.
Setting Up Working Directory
I typically like to use create-react-app
to create React apps. After installing it globally using npm
or yarn
, you can create React apps with it simply by running create-react-app <Project_Name>
. So, let’s create a React app in the root directory of our project. Run create-react-app client
.
Now, let’s install the packages we will use in our React app. Run npm install react-icons react-router-dom sweetalert-react
. We will also need babel-loader
as a dev dependency. So, run npm install babel-loader --save-dev
to install it.
Alright, now, let’s clean up some extra files. Delete the following files from your client
directory.
public/favicon.ico public/logo192.png public/logo512.png public/manifest.json src/App.css src/App.test.js src/logo.svg src/setupTests.js
NOTE: Do not forget to remove the lines that were using/calling these files from public/index.html
andsrc/App.js
.
Creating Routes with React Router
First, create a components
folder in src
folder. Then, create a folder called App
inside components
and move App.js
to there. Make sure to update the import
line in index.js
. Now, inside index.js
, let’s wrap our App
component with a Router
component as follows.
Next, we need to create components for the pages, so that we can tell React Router to use them when corresponding routes are matched. Create a pages
folder in src
and add Home
, Login
, Register
and Error404
folders in there. Afterwards, create <PAGE_NAME>.js
and <PAGE_NAME>.css
files in each of the pages’ folders. Then, create a simple component in each of the .js
files so that we can see the Router working. For example, here is pages/Home/Home.js
.
Last but not least, we need to actually define the routes in App.js
.
The Switch
component is used to return only one matching route. We use the Route
component to define a route. The component
prop defines the component to return when the URL
matches the path
prop. We also use the exact
prop to indicate that we want to return a component only when the URL
exactly matches path
. To expand on this, consider the URL
'/login'
, when React Router tries to return a component for that route, it finds that both '/'
and '/login'
are matched to that route, so it returns both of them. And the route on line 15
is basically telling React Router to use that Error404
component for any URL
not matching the ones mentioned above.
Creating Components
Before we continue on with creating the pages components, we first need to create Form
and InputField
components to use them in pages components.
First, create Form
and InputField
folders in src/components
and create <Component_Name>.js
and <Component_Name>.css
files in each of these folders.
InputField Component
Let’s start with InputField
. Here is InputField.js
.
And this is InputField.css
.
And here is a demonstration of the markup.
Form Component
Here is Form.js
.
As you can see, it returns a form
element with the children passed to it and a button. I did so to be able to use it in both Login
and Register
pages as both of them have different InputField
s.
And this is Form.css
:
Creating Register Page
Although we haven’t created the NavBar
component yet, we are ready to create the Register
and Login
pages.
First, let’s create a simple class component and import things we are going to use.
For the sake of proper styling, we will use a couple of lifecycle methods to center the register form and give a sweet gradient background to the body.
The point here is that if we were to put these styles in Register.css
, and because of the way React Router
works, they would be used on all pages. So, we apply them when the component is mounted
and revert their effect when the component is being unmounted
.
And here is the markup of the Register
page. These lines are placed inside the .register
div.
First we have a div containing the avatar at the top of the form. Then we have the form represented in a Form
component. And inside of it we have four InputField
components for username
, email
, password
and confirm password
. At the end we have a Link
component to the login
page, to provide the user a way to go to the login page.
Finally, we need to define a state
to keep track of the values of input fields. We also need to define handleFormSubmit
and handleInputChange
functions to control the form and inputs.
In handleFormSubmit
, we will just console.log('FORM SUBMITTED')
for now, and will come back to it when we create the Users
context
. In handleInputChange
, we use the name property of event.target
as a key and its value as a value
to update the state.
NOTE: I am using arrow functions because they do not have their own this
, which means if you call this.setState()
from an arrow function in a class component, it will look for the setState()
function in the component, not inside the function itself. You could overcome the this
problem in another way using bind()
.
And to finish up, here is Register.css
.
We also need to add following lines to index.css
.
NOTE: Do not forget to add 'root'
class to the div
with the id 'root'
in public/index.html
.
Creating Login Page
The Login
page component is very similar to the Register
one, with some slight noncore differences. You can have a look at Login.js
and Login.css
on the GitHub repository.
Creating Error404 Page
This page’s component is super simple. We have some text and a Link
to /
that we will style to make it look like a button. And here is Error404.css
.
Conclusion
First, we created a new React app using create-react-app
, and cleaned up extra files. Then, we defined our app routes using React Router
. Afterwards, we created some components to use when creating the pages. Finally, we created components for some pages. In the next part, we will create a Users Context
to connect Frontend to Backend. We will also complete working on the components we couldn’t create because they need the Users Context
.
NOTE: You can find all parts of this tutorial here and code here.