Today we will learn and practice ReactJs by building a mortgage calculator step by step. This is the project that we will build today π
Objectives
The topics we'll cover while building this project are:
- React Functional Components
- Material UI
- User Inputs
- Handling Props
- props destructuring
- useState Hook
And much more! This course is excellent for beginners who want to learn ReactJs by building a real world project.
You can watch this tutorial on YouTube as well if you like:
Table of Contents
- Project Setup
- Folder Structure
- Material UI Theme
- How to Build the Navbar
- Material UI Grid System
- How to Build the Slider Component
- Take a Break
- How to Use the useState Hook
- How to Build the SliderSelect component
- How to Build the TenureSelect component
- How to Build the Result Component
- Conclusion
- My Social Media Links
Project Setup
In order to setup the project we need to install react
, material-ui
, and other necessary packages.
First create a folder named mortgage-calculator
, open it on VS Code, and then run the following command in the terminal:
npx create-react-app .
npm install @mui/material @emotion/react @emotion/styled
npm install --save chart.js react-chartjs-2
App.js
We will remove all the boilerplate code from app.js
and keep up to this portion π
import React from "react";
function App() {
return <div className="App">Hello everyone</div>;
}
export default App;
Then run this command in the terminal to start the server:
npm start
The project should look totally blank on the web browser now.
Let's start coding
Everything is setup and ready to go. Now we will start building the project :)
Folder Structure
Our folder structure should look like this so that we can easily manage and maintain our files & folders:
mortgage-calculator/
βββ src/
β βββ Components/
β β βββ Common/
β β β βββ SliderComponent.js
β β βββ Navbar.js
β β βββ Result.js
β β βββ SliderSelect.js
β β βββ TenureSelect.js
β βββ theme.js
β βββ App.js
β βββ index.js
βββ .gitignore
βββ package.json
βββ package-lock.json
Here's an image of our project folder structure if you're feeling confused:
Material UI Theme
We will be using the dark theme of Material UI. For that we need to create a file named theme.js
in the src
folder and add the following code:
theme.js
import { createTheme } from '@mui/material/styles';
export const theme = createTheme({
palette: {
mode: 'dark',
},
})
index.js
Next up, we need to import the theme
in the index.js
file and wrap the app with the ThemeProvider
. Follow along below: π
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { theme } from "./theme";
<React.StrictMode>
<ThemeProvider theme={theme}>
<App />
<CssBaseline />
</ThemeProvider>
</React.StrictMode>
Note: If you don't pass the CssBaseline
component we will not be able to see the MUI dark theme.
This is the result so far: π
The entire screen will be dark. This means that dark mode has been applied to our project from Material UI.
How to Build the Navbar
Next up, we will be creating a very simple Navbar to show the Logo. For that we need to create a file named Navbar.js
in the src/Components
folder and add the following code:
Navbar.js
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import { Container } from "@mui/system";
const Navbar = () => {
return (
<AppBar position="static">
<Container maxWidth='xl'>
<Toolbar>
<Typography variant="h5">
Bank of React
</Typography>
</Toolbar>
</Container>
</AppBar>
);
};
export default Navbar;
Here's a quick explanation of the components used from Material UI:
- AppBar : The Appbar component of Material UI is used for creating a top navigation bar in the user interface. Read more about it here
- Container : The Container component of Material UI is used for creating a container element that can be used to create a responsive layout, and center and contain other elements in a user interface. Read more about it here
- ToolBar : The Toolbar component can contain elements such as buttons, text, and icons, and can also be used for creating a responsive layout that adapts to different screen sizes. Read more about it here
- Typography : Material UI's typography component is used for applying pre-defined typographic styles to text elements. It helps create a consistent and visually pleasing layout with customizable font family, size, weight and spacing. Read more about it here
App.js
Finally, import it to App.js
and write the code like this: π
import React from "react";
import Navbar from "./Components/Navbar";
function App() {
return (
<div className="App">
<Navbar />
</div>
);
}
export default App;
This is the result so far: π
Material UI Grid System
In the finalized project, we can see that our content is divided into 2 portions. On the left we have the slider components and on the right we have the pie chart. This is made possible using the Grid system of material UI.
Not only that, we can also see that the content is responsive on smaller screen sizes. This is also made possible using the Grid system of material UI.
To replicate this, we need to write these things on our App.js file. You can follow along here. π
First of all, we need to import all of our required components from Material UI and our components folder:
import React, { useState } from "react";
import { Grid } from "@mui/material";
import { Container } from "@mui/system";
import Navbar from "./Components/Navbar";
import Result from "./Components/Result";
import SliderSelect from "./Components/SliderSelect";
import TenureSelect from "./Components/TenureSelect";
Next up, we write this code inside the return
statement like this: π
<div className="App">
<Navbar />
<Container maxWidth="xl" sx={{marginTop:4}}>
<Grid container spacing={5} alignItems="center">
<Grid item xs={12} md={6}>
<SliderSelect />
<TenureSelect />
</Grid>
<Grid item xs={12} md={6}>
<Result/>
</Grid>
</Grid>
</Container>
</div>
Explanation of the code:
- Container: On the
Container
we wrote something calledsx={{marginTop:4}}
. This is the way to add inline-style to a component in Material UI. - Grid: The Grid component is used to create a responsive layout that adapts to different screen sizes.
Grid container
represents the parent element andGrid item
represents the child element. - On the
Grid
component we wrote something calledspacing={5}
. This is the way to add spacing between the grid items. - On the
Grid
component we also wrotexs={12}
which means that the grid item will take up the entire width of the screen on extra small screens. Similarly,md={6}
means that the grid item will take up half of the screen on medium and bigger screens. That's how we made our components responsive.
This is the result so far: π
How to Build the Slider Component
Next up, we will be creating a slider component to get the input amount from the user. It will look something like this: π
For that we need to create a file named SliderComponent.js
in the src/Components/Common
folder. First let's list out all the props we need to pass to our re-usable slider component:
- label
- min
- max
- defaultValue
- unit
- value
- steps
- amount
- onChange
SliderComponent.js
Let's get going. First of all, import the following components from MUI inside the SliderComponent.js
file:
import React from "react";
import Slider from "@mui/material/Slider";
import { Typography } from "@mui/material";
import { Stack } from "@mui/system";
We will be using the Stack component from MUI to stack the components vertically. my
is the shorthand for marginY
[margin-top & margin-bottom]. We will be using the Typography
component from MUI to display the label, unit, and other data. We will be using the Slider
component from MUI to display the slider.
Write this small amount of code first, with our props destructured:
const SliderComponent = ({
defaultValue,
min,
max,
label,
unit,
onChange,
amount,
value,
steps
}) => {
return (
<Stack my={1.4}>
</Stack>
)
}
export default SliderComponent
We will write this code to display the label, unit, and amount.
<Stack gap={1}>
<Typography variant="subtitle2">{label}</Typography>
<Typography variant="h5">
{unit} {amount}
</Typography>
</Stack>
We will write this code to display the slider. We will be passing the props to the slider component like this: π
<Slider
min={min}
max={max}
defaultValue={defaultValue}
aria-label="Default"
valueLabelDisplay="auto"
onChange={onChange}
value={value}
marks
step={steps}
/>
We will write this code to display the min and max values of the slider. We will be using the Stack
component from MUI to stack the components horizontally. direction="row"
is the shorthand for flex-direction: row
. justifyContent="space-between"
is the shorthand for justify-content: space-between
.
<Stack direction="row" justifyContent="space-between">
<Typography variant="caption" color="text.secondary">
{unit} {min}
</Typography>
<Typography variant="caption" color="text.secondary">
{unit} {max}
</Typography>
</Stack>
Good Job so far!
Take a break
Take a break β you deserve it! π
How to Use the useState Hook
We need to use the useState hook from React in our project. But before that, we need to understand what this hook is and why we need to use it.
The useState hook is a built-in React function that allows you to add state to functional components. It returns an array
containing two elements: the current state value and a function to update that value. The general syntax of the useState hook is as follows:
const [state, setState] = useState(initialState);
Here's what's going on: π
state
: The name of the constant or variable that will store the state.setState
: A function to update the state.initialState
: The initial value of the state.
Example of the useState hook
We will create a toggle button that changes its text between "ON" and "OFF" when clicked.
import React, { useState } from 'react';
const ToggleButton = () => {
const [isOn, setIsOn] = useState(false);
const toggle = () => setIsOn(!isOn)
return (
<button onClick={toggle}>{isOn ? 'ON' : 'OFF'}</button>
);
};
export default ToggleButton;
Here, we initialize the isOn
state with an initial value of false
. The toggle
function updates the isOn
state to its opposite value when the user clicks the button. We use a ternary operator
to render the text inside the button based on the current value of isOn
.
App.js
Now lets come back to our project. First, come over to the App.js
file and import the useState
hook from React.
import React, { useState } from 'react';
Next up, we will declare a state to store the value of the sliders using the useState
hook. We will be passing the initial value of the state as {}
inside the useState
hook, because we are storing our data as an object.
function App() {
const [data, setData] = useState({})
// other codes are here
}
We're using the useState hook to create a new state variable called data
and a function called setData
that we can use to update the state.
Next up, we will pass these values as default values for our slider component.
function App() {
const [data, setData] = useState({
homeValue: 3000,
downPayment: 3000 * 0.2,
loanAmount: 3000 * 0.8,
loanTerm: 5,
interestRate: 5,
})
// other codes are here
}
Then, we will be passing the data
and setData
state as a prop to the SliderSelect
component like this: π
<div className="App">
<Navbar />
<Container maxWidth="xl" sx={{marginTop:4}}>
<Grid container spacing={5} alignItems="center">
<Grid item xs={12} md={6}>
{/* this is where we write the code π */}
<SliderSelect data={data} setData={setData}/>
<TenureSelect />
</Grid>
<Grid item xs={12} md={6}>
<Result/>
</Grid>
</Grid>
</Container>
</div>
How to Build the SliderSelect Component
So now that we have our re-usable SliderComponent
ready, let's use it in our SliderSelect.js
component. First of all, import the SliderComponent
component from the Common
folder.
SliderSelect.js
import SliderComponent from "./Common/SliderComponent";
Next up, we will destructure our props that we are receiveing from App.js
. And also, we'll create a variable called bank_limit
and assign it a value of 10000
. This represents the maximum amount of money a person can borrow from our bank.
import React from "react";
import SliderComponent from "./Common/SliderComponent";
const SliderSelect = ({ data, setData }) => {
const bank_limit = 10000;
return (
<div>
</div>
);
};
export default SliderSelect;
Next up, we will use our SliderComponent
to display the slider named Home Value
. Here we will pass the props like this to the SliderComponent
component.
const SliderSelect = ({ data, setData }) => {
const bank_limit = 10000;
return (
<div>
<SliderComponent
onChange={(e, value) => {
setData({
...data,
homeValue: value.toFixed(0),
downPayment: (0.2 * value).toFixed(0),
loanAmount: (0.8 * value).toFixed(0),
});
}}
defaultValue={data.homeValue}
min={1000}
max={bank_limit}
steps={100}
unit="$"
amount={data.homeValue}
label="Home Value"
value={data.homeValue}
/>
</div>
);
};
Here's the result so far: π
In the same way, we will create the sliders for Down Payment
and Loan Amount
like this: π
return (
<div>
{/* other codes are here */}
<SliderComponent
onChange={(e, value) =>
setData({
...data,
downPayment: value.toFixed(0),
loanAmount: (data.homeValue - value).toFixed(0),
})
}
defaultValue={data.downPayment}
min={0}
max={data.homeValue}
steps={100}
unit="$"
amount={data.downPayment}
label="Down Payment"
value={data.downPayment}
/>
<SliderComponent
onChange={(e, value) =>
setData({
...data,
loanAmount: value.toFixed(0),
downPayment: (data.homeValue - value).toFixed(0),
})
}
defaultValue={data.loanAmount}
min={0}
max={data.homeValue}
steps={100}
unit="$"
amount={data.loanAmount}
label="Loan Amount"
value={data.loanAmount}
/>
</div>
);
Again, here's the result so far: π
Finally we will create the slider for our Interest Rate
. You can follow along here: π
return (
<div>
{/* other codes are here */}
<SliderComponent
onChange={(e, value) =>
setData({
...data,
interestRate: value,
})
}
defaultValue={data.interestRate}
min={2}
max={18}
steps={0.5}
unit="%"
amount={data.interestRate}
label="Interest Rate"
value={data.interestRate}
/>
</div>
);
Here's the result so far: π
How to Build the TenureSelect Component
Next up, we will build the TenureSelect
component. This component will be used to select the tenure of the loan. It will look like this: π
App.js
First of all, pass the data
and setData
state as a prop to the TenureSelect
component like this: π
return (
<div className="App">
<Navbar />
<Container maxWidth="xl" sx={{marginTop:4}}>
<Grid container spacing={5} alignItems="center">
<Grid item xs={12} md={6}>
<SliderSelect data={data} setData={setData} />
{/* this is where we write the code π */}
<TenureSelect data={data} setData={setData}/>
</Grid>
<Grid item xs={12} md={6}>
<Result data={data}/>
</Grid>
</Grid>
</Container>
</div>
);
TenureSelect.js
Then, import these required components from the MUI
library:
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
Then destructure the props that we are receiving from App.js
. Also create a function named handleChange
that will be used to set the tenure
state, like this: π
const TenureSelect = ({ data, setData }) => {
const handleChange = (event) => {
setData({...data, loanTerm: event.target.value});
};
return ()
};
export default TenureSelect;
Next up, we will build the TenureSelect
component. It will look like this: π
return (
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Tenure</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={data.loanTerm}
label="Tenure"
defaultValue={5}
onChange={handleChange}
>
<MenuItem value={5}>5 years</MenuItem>
<MenuItem value={10}>10 years</MenuItem>
<MenuItem value={15}>15 years</MenuItem>
<MenuItem value={20}>20 years</MenuItem>
<MenuItem value={25}>25 years</MenuItem>
</Select>
</FormControl>
);
The result so far: π
How to Build the Result Component
Finally we will build the Result
component. This component will be used to display the loan installment per month and the pie chart. It will look like this: π
App.js
First of all, pass the data
state as a prop to the Result
component like this: π
return (
<div className="App">
<Navbar />
<Container maxWidth="xl" sx={{marginTop:4}}>
<Grid container spacing={5} alignItems="center">
<Grid item xs={12} md={6}>
<SliderSelect data={data} setData={setData} />
<TenureSelect data={data} setData={setData}/>
</Grid>
<Grid item xs={12} md={6}>
{/* this is where we write the code π */}
<Result data={data}/>
</Grid>
</Grid>
</Container>
</div>
);
Result.js
Next up, import the required components like this: π
import React from "react";
import { Stack, Typography } from "@mui/material";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import { Pie } from "react-chartjs-2";
ChartJS.register(ArcElement, Tooltip, Legend);
Then destruct the data
state that we are receiving from App.js
like this: π
const Result = ({ data }) => {
const { homeValue, loanAmount, loanTerm, interestRate } = data;
return ();
};
export default Result;
Next up we will write all of these things that will help us do the calculation: π
const totalLoanMonths = loanTerm * 12;
const interestPerMonth = interestRate / 100 / 12;
const monthlyPayment =
(loanAmount *
interestPerMonth *
(1 + interestPerMonth) ** totalLoanMonths) /
((1 + interestPerMonth) ** totalLoanMonths - 1);
const totalInterestGenerated = monthlyPayment * totalLoanMonths - loanAmount;
Then we need this variable to store all the data for our pie chart, like this: π
const pieChartData = {
labels: ["Principle", "Interest"],
datasets: [
{
label: "Ratio of Principle and Interest",
data: [homeValue, totalInterestGenerated],
backgroundColor: ["rgba(255, 99, 132, 0.2)", "rgba(54, 162, 235, 0.2)"],
borderColor: ["rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)"],
borderWidth: 1,
},
],
};
Finally, we will build the Result
component. It will look like this: π
return (
<Stack gap={3}>
<Typography textAlign="center" variant="h5">
Monthly Payment: $ {monthlyPayment.toFixed(2)}
</Typography>
<Stack direction="row" justifyContent="center">
<div>
<Pie data={pieChartData} />
</div>
</Stack>
</Stack>
);
Here's the final result: π
Conclusion
Congratulations for reading until the end! Now you can confidently and efficiently use React JS and Material UI to build cool projects.
You have also learned how to use React's useState hook and how to handle props. I hope you enjoyed this tutorial.
Mentorship Program
If you are interested in learning more about React JS and web development, I am offering a mentorship program. You can check out the details here π Mentor Labs Academy