Rui Fernandes

A simple and objective way to learn React.js

by Rui Fernandes -

Imagem de cover

What is React?

React is a JavaScript library focused on creating user interfaces, in general. With React, you can build:

Why using React?

Prerequisites

To start with React, you need to know:

Basic concepts

JSX (JavaScript XML)

When you use React inside your project, JavaScript will be responsible for rendering all DOM elements.

So, considering the following vanilla JS code that renders a h1 with the Hello World text:

const element = document.createElement('h1');
element.innerHTML = "Hello World";

React has an easier way to do that:

const element = <h1>Hello World</h1>;

That is not HTML. Actually it is JSX, a XML syntax inside JavaScript. With that syntax, you can build entire components inside a JavaScript code. React's official documentation notes that "React doesn’t require using JSX, but most people find it helpful as a visual aid when working with UI inside the JavaScript code. It also allows React to show more useful error and warning messages".

Components

Let's suppose that you want to build a Discord-like web app:

Discord interface

In that interface, we notice that several elements represent the same thing, for instance, "information" and "rules", that represent text channels. Because of that, we can reuse their code, creating one component: the TextChannel component. To create a component, you'll need to declare a function (with a capital letter) that returns JSX.

function TextChannel(props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <h2>{props.subtitle}</h2>
    </div>
  );
}

That is called function component. React also has class components, but in this article, we'll work only with function components.

Notice that the function has an argument called props (properties), which is an object with data from somewhere (we'll see further).

To create each channel, we can instantiate them with self-closing tags (the final slash is required, in that case) or paired tags:

// Self-closing tags
const informationChannel = <TextChannel title="information" subtitle="Server information" />;

// Paired tags
const rulesChannel = <TextChannel title="rules" subtitle="Server rules"></TextChannel>;

Each channel has two properties: title and subtitle. These properties are passed to the TextChannel component through the props object.

Rendering the information channel:

ReactDOM.render(
  informationChannel,
  document.getElementById('root')
);

Rendering the rules channel:

ReactDOM.render(
  rulesChannel,
  document.getElementById('root')
);

Note: in practice, we'll not call the render method for each component. We'll see the right way below (one render method call to the entire application).

Hands on

Creating and running the project

If you use yarn:

yarn create react-app hello-world-app
cd hello-world-app
yarn start

If you use npm:

npx create-react-app hello-world-app
cd hello-world-app
npm start

So, now you'll be redirected to http://localhost:3000.

Initial structure

├── [ 36K]  node_modules
├── [ 819]  package.json
├── [4.0K]  public
│   ├── [3.8K]  favicon.ico
│   ├── [1.7K]  index.html
│   ├── [5.2K]  logo192.png
│   ├── [9.4K]  logo512.png
│   ├── [ 492]  manifest.json
│   └── [  67]  robots.txt
├── [3.3K]  README.md
├── [4.0K]  src
│   ├── [ 564]  App.css
│   ├── [ 528]  App.js
│   ├── [ 246]  App.test.js
│   ├── [ 366]  index.css
│   ├── [ 500]  index.js
│   ├── [2.6K]  logo.svg
│   ├── [ 362]  reportWebVitals.js
│   └── [ 241]  setupTests.js
└── [498K]  yarn.lock

You can delete:

So, you'll need to refactor:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <title>Hello World App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

Notice that public/index.html has a div with id "root". React renders all the components inside that div. The cool thing is when you go to different places on your websites, like "/contact" or "/about", the page won't need to refresh. It happens because React stores the state of DOM inside a Virtual DOM, so when something changes, React will render only the changes, not the entire DOM, increasing the performance of the application and, by consequence, the User Experience. Because of that, React applications are called Single Page Application (SPA).

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

We see that React gets the main component of the application (<App />) and renders it into a DOM element. In this case, the div#root from public/index.html.

import React from 'react';

function App() {
  return (
    <h1>Hello World</h1>
  );
}

export default App;

Now, using the Discord example:

  1. Create a TextChannel.js file inside the src folder;
  2. Import React;
  3. Create the TextChannel function component;
  4. Export it.
import React from 'react';

function TextChannel(props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <h1>{props.subtitle}</h1>
    </div>
  );
}

export default TextChannel;

State

In the Discord example, how could I switch between two text channels? One way to do this is by storing the current channel in someplace and rendering it every time I switch. How to do that in React?

React has a concept called state. The state is responsible for storing data that might be changed during the component's life cycle, influencing the render output.

If you use function components, you'll need to use the useState hook. Hooks are functions that help you to use state and other React features without implementing a class.

The useState has one parameter (the initial value of the state), and it returns an array with two elements:

In practice (src/App.js):

import React, { useState } from 'react';
					
function App() {
  const [currentChannel, setCurrentChannel] = useState(null); // Destructuring the array into two variables
    
  (...)
}

export default App;

Now, let's create an array with all text channels (in that case, it won't need to be stored in a state because it won't be changed during the component's life cycle):

import React, { useState } from 'react';
					
function App() {
  const [currentChannel, setCurrentChannel] = useState(null);
    
  const allTextChannels = [
    { title: "information", subtitle: "Server information" },
    { title: "rules", subtitle: "Server rules" },
  ]
  
  (...)
}

export default App;

Let's render two buttons to switch the channels. Each button will have an onClick property. Notice that, in HTML, it would be on-click. It happens because JSX doesn't accept hyphens, so all HTML properties need to be written in camelCase.

We will pass to onClick a function (arrow function) that changes the current text channel through the setCurrentTextChannel function.

(...)
 return (
   <div>
    <h1>Hello World</h1>
    <button onClick={() => setCurrentTextChannel(allTextChannels[0])}>
      Information
    </button>
    <button onClick={() => setCurrentTextChannel(allTextChannels[1])}>
      Rules
    </button>
  </div>
 );
(...)

Now, we need to display the current channel. In this case, we'll need to validate if the current channel was chosen by the user or not. But it's not possible to use the if/else statement inside JSX, so we'll use the ternary operator:

(...)
 return (
   <div>
    <h1>Hello World</h1>
    <button onClick={() => setCurrentTextChannel(allTextChannels[0])}>
      Information
    </button>
    <button onClick={() => setCurrentTextChannel(allTextChannels[1])}>
      Rules
    </button>

    {
      currentTextChannel
      ?
      <TextChannel title={currentTextChannel.title} subtitle={currentTextChannel.subtitle} />
      :
      <p>Choose one channel</p>
    }
  </div>
 );
(...)

What does it mean?

    {
      currentTextChannel // currentTextChannel is truthy? (*)
      
      ? // If it is truthy (*) (currentTextChannel was chosen, so render it)
      
      <TextChannel title={currentTextChannel.title} subtitle={currentTextChannel.subtitle} />
          
      : // Else (currentTextChannel was not chosen.)
      
      <p>Choose one channel</p>
    }

(*) Truthy: value different from 0, 0n, null, undefined, false, NaN or "". In the case of our code, the initial value of currentChannel is null, so the code will know if no channel was chosen. Because of that, this validation is required.

Result

Congrats! Now you learned the basic concepts of React and can apply them in the real world. If you want to deepen your knowledge, I highly recommend the React's official documentation.

Thanks for reading!

References

React's official documentation

JavaScript Truthy and Falsy

Rui Fernandes

Rui Fernandes

Focused Full Stack Engineer creating impactful digital solutions.