React Fundamentals: A Beginner’s Guide to Building Web Apps

A JavaScript framework is a pre-written collection of libraries that provide developers with a foundation for building web applications. These frameworks offer reusable components, tools, and a structured way to organize code, making it easier to develop and maintain complex applications.

Why do you need a JavaScript framework like React

Using a JavaScript framework can significantly accelerate the software development cycle. For instance, you are building a counter that counts how many times a button has been clicked, how would you approach this problem?

To achieve this using plain JavaScript, you must have a decent understanding of the DOM and how to manipulate the DOM tree, which means your code probably looks like this:

javascript
1let count = 0;
2
3const counterDiv = document.createElement("div");
4const p = document.createElement("p");
5const button = document.createElement("button");
6
7p.textContent = `You clicked ${count} times`;
8button.textContent = "Click me";
9
10button.addEventListener("click", () => {
11  count += 1;
12  p.textContent = `You clicked ${count} times`;
13});
14
15counterDiv.appendChild(p);
16counterDiv.appendChild(button);
17document.body.appendChild(counterDiv);

This example involves a lot of DOM handling methods and properties such as createElement(), appendChild(), and textContent. These methods are not easy to grasp and it is difficult to visualize in your head how the user interface should look like while micromanaging each DOM node.

This is why React.js was created. It allows you to describe how the UI should look like, and React will handle what to do at each DOM node. For example,

jsx
1import React, { useState } from "react";
2
3function Counter() {
4  const [count, setCount] = useState(0);
5
6  return (
7    <div>
8      <p>You clicked {count} times</p>
9
10      <button onClick={() => setCount(count + 1)}>Click me</button>
11    </div>
12  );
13}
14
15export default Counter;

As you can see, using React, you can describe the UI directly using HTML, with a few more things that extends its capabilities, such as data interpolation ({count}) and hooks (useState(0)). We will discuss more about these concepts in future lessons.

Getting started with React

Many people see React as more of a library than a framework because it is much more flexible than other frameworks. As we've discussed before, frameworks allow you to organize your code in a organized manner. However, that also means you must obey certain rules and follow a strict project structure.

However, that is not the case for React.

Getting started with React is extremely easy. All you need to do is import three JavaScript files into your HTML file.

html
1<!DOCTYPE html>
2<html>
3  <head>
4    <meta charset="UTF-8" />
5    <title>Hello World</title>
6    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
7    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
8    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
9  </head>
10
11  <body>
12    <div id="root"></div>
13    <script type="text/babel">
14      function MyApp() {
15        return <h1>Hello, world!</h1>;
16      }
17
18      const container = document.getElementById("root");
19      const root = ReactDOM.createRoot(container);
20      root.render(<MyApp />);
21    </script>
22  </body>
23</html>

In this example, react is the core component of the React framework, react-dom provides DOM-specific methods that allow you to work with the DOM in web applications. Their difference is that react is concerned with building components and managing their state and lifecycle, and react-dom takes care of rendering those components to the DOM.

And lastly, babel is a JavaScript compiler that allows you to use advanced language features such as JSX, which we are going to discuss later. Pay attention to the <script> tag on line 13, and notice that we have type="text/babel". This tells the browser that the code inside should be compiled with Babel.

Inside the <script> element, we have our first React app.

jsx
1function MyApp() {
2  return <h1>Hello, world!</h1>;
3}
4
5const container = document.getElementById("root");
6const root = ReactDOM.createRoot(container);
7root.render(<MyApp />);

From line 1 to 3, we defined a MyApp() function, which returns an HTML element.

Line 5 and 6 grabs the HTML tag with id="root" and creates a root element using the react-dom we just imported.

And lastly, line 7, MyApp will be rendered under this root element.

Open this HTML file inside your browser, and the following page should be rendered.

React Hello World

Open the Developer Tools to inspect the page, and you should see the <h1> tag under the #root element.

jsx
1<body>
2  <div id="root">
3    <h1>Hello, world!</h1>
4  </div>
5  <script type="text/babel">. . .</script>
6</body>

But wait, we are seeing some strange things happening here. What exactly is <MyApp />? We defined MyApp() as a function, but why are we rendering it as if it is an HTML element?

This is, in fact, what JSX is all about. It is a syntax wrapper that allows us to work with HTML inside JavaScript, using a much simpler syntax. Without it, we’ll have to render the element like this:

js
1function MyApp() {
2  return React.createElement("h1", null, "Hello, world!");
3}
4
5const container = document.getElementById("root");
6const root = ReactDOM.createRoot(container);
7root.render(React.createElement(MyApp));

We’ll come back to the topic of JSX later.

Creating a new React project using Vite

In practice, using like this isn't suitable for a production-ready project. Instead, you’ll need an actual React project in order to unleash its full power.

The React team used to maintain a command-line tool called create-react-app, which allows you to easily initialize a new React app. However, this tool was deprecated in 2023. Nowadays, the go-to method for creating a React application is using Vite.

Vite is a modern frontend build tool that is known for its fast development server with native support for Hot Module Replacement (HMR), which is a technology that allows developers to apply code updates in real time without having to refresh the entire page.

To initialize a new project using Vite, run the following command:

bash
1npm create vite@latest <my_project>

You will then be prompted to select a framework. Make sure you select React, and hit Enter.

1? Select a framework: › - Use arrow-keys. Return to submit.
2    Vanilla
3    Vue
4❯   React
5    Preact
6    Lit
7    Svelte
8    Solid
9    Qwik
10    Others

Vite will then ask if you opt to use TypeScript and SWC (Speedy Web Compiler), a faster alternative to Babel. For now, we'll stick to JavaScript to make things easier. We will discuss how to upgrade to TypeScript later.

1? Select a variant: › - Use arrow-keys. Return to submit.
2    TypeScript
3    TypeScript + SWC
4    JavaScript
5❯   JavaScript + SWC
6    Remix ↗

Select JavaScript + SWC and hit Enter, and you should see the following output:

text
1✔ Select a framework: › React
2✔ Select a variant: › JavaScript + SWC
3
4Scaffolding project in /. . ./reactjs-demo/reactjs-demo...
5
6Done. Now run:
7
8  cd <my_project>
9  npm install
10  npm run dev

Follow the instructions and change into the project directory, install the necessary packages, and start the dev server.

text
1VITE v5.3.5  ready in 393 ms
2
3  ➜  Local:   http://localhost:5173/
4  ➜  Network: use --host to expose
5  ➜  press h + enter to show help

Open the browser and visit http://localhost:5173/, and you should see the following page.

Vite

React project structure

Now, let’s take a look at what Vite has created for us.

1.
2├── README.md
3├── index.html
4├── package-lock.json
5├── package.json
6├── public
7│   └── vite.svg
8├── src
9│   ├── App.css
10│   ├── App.jsx
11│   ├── assets
12│   │   └── react.svg
13│   ├── index.css
14│   └── main.jsx
15└── vite.config.js

We have two directories, src and public. src contains the source code for our React application, and public contains the files that are directly accessible to the user, such as images, videos, and so on.

As for the files, let’s start with the root directory. First of all, you should see the index.html. This is the entry point of our project. When you visit http://localhost:5173/, this is the file that is served to your browser.

index.html

html
1<!DOCTYPE html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7    <title>Vite + React</title>
8  </head>
9
10  <body>
11    <div id="root"></div>
12    <script type="module" src="/src/main.jsx"></script>
13  </body>
14</html>

Notice that instead of importing three different JavaScript files, we are only importing one. This is another benefit of using a build tool like Vite. It will automatically bundle everything we need into one single file, improving the performance of your application.

Next, we have vite.config.js, the configuration file for Vite. We are not going to talk too much about this, as this is not a course on Vite, but if you are interested, check out Vite’s official documentation for details.

vite.config.js

jsx
1import { defineConfig } from "vite";
2import react from "@vitejs/plugin-react-swc";
3
4// https://vitejs.dev/config/
5export default defineConfig({
6  plugins: [react()],
7});

Inside the src directory, we have the main.jsx file. This is the file that was imported into index.html. Notice that it has the file extension .jsx, which means this file contains JSX instead of regular JavaScript code. We are going to discuss JSX in detail later, but for now, let’s pretend we are working with plain JavaScript.

src/main.jsx

jsx
1import React from "react";
2import ReactDOM from "react-dom/client";
3import App from "./App.jsx";
4import "./index.css";
5
6ReactDOM.createRoot(document.getElementById("root")).render(
7  <React.StrictMode>
8    <App />
9  </React.StrictMode>
10);

Take a closer look at this main.jsx, it looks a lot like our previous example, where we imported the React packages directly without using Vite. getElementById("root") retrieves the element with id=”root”, createRoot() anchors that element as the root, and finally render() renders new elements under the root. The only difference is that in this example, we have the StrictMode enabled, which is a tool in React for highlighting potential errors in your code.

Also notice that the App() function is imported from another file, App.jsx, which looks like this:

src/App.jsx

jsx
1import { useState } from "react";
2import reactLogo from "./assets/react.svg";
3import viteLogo from "/vite.svg";
4import "./App.css";
5
6function App() {
7  const [count, setCount] = useState(0);
8
9  return (
10    <>
11      <div>
12        <a href="https://vitejs.dev" target="_blank">
13          <img src={viteLogo} className="logo" alt="Vite logo" />
14        </a>
15        <a href="https://react.dev" target="_blank">
16          <img src={reactLogo} className="logo react" alt="React logo" />
17        </a>
18      </div>
19      <h1>Vite + React</h1>
20      <div className="card">
21        <button onClick={() => setCount((count) => count + 1)}>
22          count is {count}
23        </button>
24        <p>
25          Edit <code>src/App.jsx</code> and save to test HMR
26        </p>
27      </div>
28      <p className="read-the-docs">
29        Click on the Vite and React logos to learn more
30      </p>
31    </>
32  );
33}
34
35export default App;

There are a few things we've never seen before. For instance, what is useState()? And what is the empty tag (<></>)? What is the curly braces ({count}) doing here?

We will answer each of these questions in future lessons. But first, let's talk about that topics we are going to discuss in this course.

What is included in this course

In this course on React, we are going to cover the following topics:

  • How to describe a user interface using JSX
  • How to conditionally render elements
  • How to render a list of elements
  • How to create reusable UI components
  • How to pass data across different components
  • How to handle events
  • How to manage states
  • How to use hooks

If you are not familiar with the concept of state management or hooks, don't worry, we are going to talk more about them when we get there.