I am assuming that if you have landed on this blog then, you are an absolute beginner in React or if you already know to react then this blog will help you to brush up on your concepts quickly. Here we will not go in very in-depth on any react concept like JSX or states, but instead, we will first use everything on a small scale and get our hands dirty so that we can see how fast React can help us to build an app that would have been extremely complex to create using plain Javascript.
We are going to just make a simple application that is going to fetch e-commerce data from Fakestore API (free to use) and we can search for different products with the power of SPA and React we will be able to make it more easily.
Setting up React project from scratch
There are some tools available using which you can get a set of boilerplate starter codes for using react. But IMO, when learning a library like react it becomes essential to understand the project setup and directory structure from scratch to understand some small details that we might not see if we use the tools.
So as React is a JS framework and deals with creating frontend applications, we will be concerning ourselves with a bunch of HTML CSS and JS code.
Open VS Code or any text editor / IDE you want to prefer. Create a folder in your drive where you want to set up the project. Open that folder in VS Code and create three files' index.html
App.js
Write the following code in your index.html file and then I will explain each bit of it to you.
<!DOCTYPE html>
<html lang="en">
<head>
<title>E-Commerce</title>
</head>
<body>
<div id="root">not rendered</div>
<script type="module" src="./App.js"></script>
</body>
</html>
Now, most of the things in the above HTML code must be simple to understand for you. If you carefully see in the <body>
tag we have a <div>
which has an id
as root
.
This div is going to be the most important part of your HTML code because technically this is the only HTML element you will be created manually in the HTML file. Rest all of your HTML elements will be prepared using JS.
So, in the browser, the HTML that we render is rendered in the form of a Tree Data structure also called as DOM
is abbreviated as Document Object model. When you prepare your frontend using react, the logic of react heavily depends on this tree data structure as react in itself prepares another tree called as React DOM
or Virtual Dom
. Now this <div>
with id
root
will be the root of the DOM and everything inside it will be managed by React. What is the use case of React Dom
or Virtual Dom
? So whenever anything changes in the DOM then react compares it with the previous state of the virtual Dom and only updates the relevant parts. For example, if there is a <h1>
and a <h2>
element and there is an update that you did use JS just to the <h2>
then not the whole DOM is re-rendered but instead only <h2>
will change.
Don't worry we will demonstrate this soon 🔥
The root element i.e. the <div>
we will get this in our JS code and manually make the root. Apart from this <div>
we also have a script tag that accesses the JS file in which we will write our React logic to handle the front end. the type
property exists because we want to specify ES6
modules although it's not mandatory to keep.
Let's start writing our JS code as well.
import React from "react";
import ReactDOM from "react-dom/client";
const App = () => {
return React.createElement(
"div",
{},
React.createElement("h1", {}, "Welcome Welcome")
);
};
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(App());
Now the above JS code is pretty self explanatory if your have already read our last blog. We are first importing React and ReactDom for getting all the important functions that are going to help us in controlling the Dom. Then we are getting the root
div and creating it the root of the DOM using ReactDOM.createRoot
. Post that we are rendering our App
inside the root, which is nothing but returning a React Element. This react element is a <div>
which is having a child element as <h1>
tag.
If you now try to run the server using npm run dev
then you must get the following output.
Voila, you have a basic react app up and running, but let's not stop here, there is a lot more that we need to do before our first app actually starts taking shape.
Adding JSX
Now in the above App.js file, we have written plain JS, using which we are converting the JS code into HTML code. Now React provides a much cooler way to write the same functionality but with a touch of HTML and JS both. Here comes JSX into the picture.
JSX is a syntax extension to JavaScript. It is recommended using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript. JSX produces React “elements”.
After compilation, JSX expressions become regular JavaScript function calls and evaluate JavaScript objects.
So let's start re-writing out the App.js file using JSX. To start with, rename the extension to JSX (not mandatory, depends on the compiler) and in the html file, update the src of the script tag to App.jsx
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>E-Commerce</title>
</head>
<body>
<div id="root">not rendered</div>
<script type="module" src="./App.jsx"></script>
</body>
</html>
Now in the App.jsx
file re-write your App
function to now includes JSX. Now to write JSX, you can return a bunch of HTML code enclosed by a pair of parenthesis. For example:
const App = () => {
return (
<div>
<h1>E-commerce Application</h1>
</div>
);
};
You can see in the above piece of code, we are just returning a <div>
containing a <h1>
which is overall wrapped inside a pair of parenthesis ()
. Now this becomes one logical unit of the UI also referred to as component. We will discuss the concept of components later in good depth.
Now we can use this App
to render in the root by mentioning it as an HTML tag <App/>
. This is the power of JSX that JS code is preferable as a more verbose HTML.
The App.jsx file will now look something like this.
import React from "react";
import ReactDOM from "react-dom/client";
const App = () => {
return (
<div>
<h1>E-Commerce Application</h1>
</div>
);
};
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
You should get the following output in the browser after making the changes.
The power of JSX is immense. You can write any JS expression in the HTML-looking JSX code, by wrapping it in a pair of curly braces. For example, you can write a valid JS expression like this in your App component.
import React from "react";
import ReactDOM from "react-dom/client";
const App = () => {
return (
<div>
<h1>Movie Application</h1>
{8 + 2}
</div>
);
};
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
The output of the above code will be like this:
The JS expression {8+10}
that we wrote in JSX is automatically evaluated by React and then it renders the output, which means any valid JS logic can be used in the JS code allowing you to add complex logic in your react code.
Congratulations, you have added your first logical piece of React code.
You might feel you have not done much but for sure my friend you have completed a lot.
Let's take the journey one step ahead, and start making one more component, and let's see how can you add one component to other.
Creating the first reusable component
Now we want to convert this app into an e-commerce searching application, we will integrate the FakeStore API so that we can search for products like e-commerce from our application. This small app will help us learn multiple aspects of the front-end development journey with React.
Let's Start making a new component, and name it as Products
component.
You need to create another file in your src directory naming Products.js
.
Write the following code in your new component:
import React from "react";
const Product = (props) => {
return React.createElement("div", {}, [
React.createElement("h1", {}, props.name),
React.createElement("img", { src: props.image }, null),
React.createElement("h3", {}, props.price),
React.createElement("p", {}, props.description),
]);
};
export default Product;
Here we are first importing the React library and then using React.createElement
function to create a div
and then inside that create h1
, img
, h2
and p
tags. Now this code is very less readable, think about using a syntax like this for an extremely long codebase like Amazon, it will be very painful. Even using props for example how we are doing it in img
tag (passing as an object in the second parameter) is very complex and will not lead to a very clean code.
Now let's convert the same code to JSX based syntax, and also change file extension to jsx.
So we will rename the file to Products.jsx
and write the following code:
import React from "react"; // using this is not mandatory
const Product = (props) => {
return (
<div>
<h1>{props.title}</h1>
<img src={props.image} alt="" />
<h2>{props.price}</h2>
<p>{props.description}</p>
</div>
);
};
export default Product;
Now in the above syntax, we have converted the createElement-
based code in JSX syntax which is definitely more readable, with a bunch of HTML-looking tags. Here Vite
is going to convert this JSX to createElement
based syntax only.
Here doing React import is not mandatory, although the JSX internally after conversion becomes something like React.createElement
so that's why you will find a lot of people importing it manually. But in the latest versions, we can skip that as it implicitly handles straightforward dependency. So final code looks like:
const Product = (props) => {
return (
<div>
<h1>{props.title}</h1>
<img src={props.image} alt="" />
<h2>{props.price}</h2>
<p>{props.description}</p>
</div>
);
};
export default Product;
One thing to note is that :
React components are regular JavaScript functions, but their names must start with a capital letter or they won’t work!
Now import this Product component in the App component.
import React from "react";
import ReactDOM from "react-dom/client";
import Product from "./Product";
const App = () => {
return (
<div>
<h1>E-Commerce Application</h1>
<Product
title="Fjallraven - Foldsack No. 1 Backpack"
price="109.95"
description="Your perfect pack for everyday use ..."
image="https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg"
/>
</div>
);
};
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
In JSX, putting a self-closing tag is mandatory. In the above code we are calling the Product
component and passing title
price
description
and image
as props which gives the look and feel of normal HTML attributes.
Now, if you go to the browser, the below output must be shown.
Note:
Wherever in the JSX you use a pair of curly braces, you write a valid evaluable JS expression inside it.
Creating our first FORM component
Now let's try to have a component that can help us to create a form using which we can take some user input and correspondingly do some actions based on that.
Let's create a new component named as Search.jsx
. In this component, we will create just a simple form.
const Search = () => {
return (
<div className="search">
<form>
<label htmlFor="category">
Category
<input id="category" placeholder="Category" />
</label>
</form>
</div>
);
};
export default Search;
Now this is a pretty simple and plain form and nothing much fancy, to be honest.
Now let's try to make this form respond to our input. We will make a variable named category
and whatever data we will input in our form we will store in that variable.
const Search = () => {
let category = "Electronics";
return (
<div className="search">
<form>
<label htmlFor="category">
Category <br />
<input id="category" placeholder="Category" /> <br />
{category}
</label>
</form>
</div>
);
};
export default Search;
Now we have a variable category and we are displaying it using {category}
Now when you will refresh for the first time, it will print Electronics
properly. Now how can we connect this variable to our form input? We can add a callback to the onChange
property and in that callback we will update the variable.
const Search = () => {
let category = "Electronics";
return (
<div className="search">
<form>
<label htmlFor="category">
Category <br />
<input
onChange={(e) => {
category = e.target.value;
console.log(category, e.target.value);
}}
id="category"
placeholder="Category"
/>{" "}
<br />
{category}
</label>
</form>
</div>
);
};
export default Search;
Now if you will open this on the browser, and check the console while typing the input, you will see that category
variable is getting the input allocated from the form, but the {cateogory}
variable is not changing from electronics.
Why is that, because category
is just a normal JS variable, but we need to make it a State variable. When a state variable changes then the component gets re-rendered.
Now how can you make a state variable (Read more about State Variable here)? You can use Hooks.
Local variables don’t persist between renders. When React renders this component a second time, it renders it from scratch—it doesn’t consider any changes to the local variables.
Changes to local variables won’t trigger renders. React doesn’t realize it needs to render the component again with the new data.
To update a react component two things need to happen:
Persist / Retain the data between renders.
Initiate React to re-render the component with new updated data.
What are hooks?
Hooks are just simple helper utilities that help us to use React features in our components like creating state variables and synchronising with external systems etc.
Let's try to use one simple hook named as useState
. This will help us to create a state variable. This function provides a state variable and a function using which you can update the state variable.
You can import useState
from react
library.
import { useState } from "react";
const Search = () => {
let [category, setCategory] = useState("");
return (
<div className="search">
<form>
<label htmlFor="category">
Category <br />
<input
onChange={(e) => {
setCategory(e.target.value);
console.log(category, e.target.value);
}}
id="category"
placeholder="Category"
/>{" "}
<br />
{category}
</label>
</form>
</div>
);
};
export default Search;
useState
function returns the two values in form of an array and we can destructure it. Here in the above example, category
is the state variable and setCategory
function will be used to update this state variable. You cannot update the state variable without using this function.
And now we are using setCategory
in the onChange
function. If you will just use an assignment variable to update it, it will not show any effect.
Now using our above code, we can start typing in our form and it will change simultaneously with the change in input.
Few points to remember about useState
The set function is responsible for updating the state variable that will be used in the next render. However, if you access the state variable after calling the set function, you will still obtain the previous value displayed on the screen.
React can optimize its performance by skipping the re-rendering of a component and its children if the new value you provide through the set function is identical to the current state, as determined by an Object.js comparison. Although in some cases, React may still need to call your component before skipping the children, it should not affect your code.
To avoid multiple re-renders during a single event, React batches state updates and update the screen only after all the event handlers have run and their set functions have been called. In rare cases where you need to force React to update the screen earlier, such as accessing the DOM, you can use
flushSync
.
Read more about this here [1] [2]
And that's a wrap for this part one of this React learning series. I will be posting part 2 of this blog post soon, where we will continue our discussion on Hooks and build more functionality on our simple e-commerce front end.
.
.
.
.
Lukewarm regards
Sanket Singh