Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions 04-frameworks/01-react/01-previous/01-concepts/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
# 01 Previous - Hi React

## Summary

In this example we are going to create a _codesandbox_ to understand the first concepts of React and the main reasons why we need a library like this.
[Here you have the complete example that we are going to develop.](https://codesandbox.io/p/sandbox/react-concepts-rncyq4)

To begin, we will start from a vanilla JavaScript project and gradually add features that bring us closer to the approach proposed by React. The goal is to see how React solves common web development problems in a more elegant and powerful way.

## Step by step

- Rename the file _index.mjs_ to _index.js_ and update the reference in _index.html_.
- Comment out all the content of _index.js_.
- In _index.html_ render a static list of users:

_index.html_

```diff
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Sandbox</title>
<meta charset="UTF-8" />
</head>

<body>
- <div id="app"></div>
+ <div id="app">
+ <h4>Lista de usuarios</h4>
+ <div>1955: Rick Sánchez</div>
+ <div>8765: Beth Harmon</div>
+ <div>7562: Farrokh Bulsara</div>
+ </div>
<script src="./index.js" type="module"></script>
</body>
</html>
```

This works, but frameworks like React offer us a different approach: they allow us to dynamically transform the DOM in the client. This way, the server only delivers a basic HTML along with a JavaScript file that generates the interface.

We leave the HTML empty and move the list into our _index.js_:

_index.html_

```diff
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Sandbox</title>
<meta charset="UTF-8" />
</head>

<body>
+ <div id="app"></div>
- <div id="app">
- <h4>Lista de usuarios</h4>
- <div>1955: Rick Sánchez</div>
- <div>8765: Beth Harmon</div>
- <div>7562: Farrokh Bulsara</div>
- </div>
<script src="./index.js" type="module"></script>
</body>
</html>
```

_index.js_:

```diff
+ import "./styles.css";

+ document.getElementById("app").innerHTML = `
+ <h4>Lista de usuarios</h4>
+ <div>1955: Rick Sánchez</div>
+ <div>8765: Beth Harmon</div>
+ <div>7562: Farrokh Bulsara</div>
+ `;
```

Now the content is generated by JavaScript. We can confirm that it’s the JavaScript file that generates the content.

### Components

Let’s start breaking our list into parts.We separate the title and the list:

````diff
import "./styles.css";

+ const Header = () => {
+ return `<h4>Lista de usuarios</h4>`;
+ };

+ const List = () => {
+ return `
+ <div>
+ <div>1955: Rick Sánchez</div>
+ <div>8765: Beth Harmon</div>
+ <div>7562: Farrokh Bulsara</div>
+ </div>`;
+ };

document.getElementById("app").innerHTML = `
+ ${Header()}
+ ${List()}
- <h4>Lista de usuarios</h4>
- <div>1955: Rick Sánchez</div>
- <div>8765: Beth Harmon</div>
- <div>7562: Farrokh Bulsara</div>
`;
```

This functions we just created, in React, are components. That is, **in React, components are functions.** For now, these components return a piece of our application, in this case the title and the list, which render something in the DOM.

### Props

Now let’s create a component that renders each user in the DOM. To do this, we’ll create a component (function) that receives a user object with an `id` and `name`:

```diff
import "./styles.css";

const Header = () => {
return `<h4>Lista de usuarios</h4>`;
};

+ const User = (props) => {
+ return `<div>${props.id}: ${props.name}</div>`;
+ };

const List = () => {
return `
<div>
+ ${User({id: 1955, name 'Rick Sánchez'})}
+ ${User({id: 8765, name 'Beth Harmon'})}
+ ${User({id: 7562, name 'Farrokh Bulsara'})}
- <div>1955: Rick Sánchez</div>
- <div>8765: Beth Harmon</div>
- <div>7562: Farrokh Bulsara</div>
</div>`;
};

document.getElementById("app").innerHTML = `
${Header()}
${List()}
`;
````

In React jargon, the input arguments we pass to components are known as `props`. A bit later we’ll see that in React, the syntax for running a component is very different from this. However, it’s very important to keep in mind that even though the syntax is different, in the end what we’re doing is invoking functions and passing them input arguments.

Let’s get a little closer to what a real application would do and simulate that the data we display in the list comes from an API. For this, let’s create a file _./api.js_.

```js
export const getUsers = () => [
{ id: 1955, name: "Rick Sánchez" },
{ id: 8765, name: "Beth Harmon" },
{ id: 7562, name: "Farrokh Bulsara" },
];
```

When invoking it inside the `List` function, we can directly use a `map` method to execute the `User` function for each element of the array, no matter how many there are.

```diff
+ import { getUsers } from './api';
import "./styles.css";

const Header = () => {
return `<h4>Lista de usuarios</h4>`;
};

+ const User = (props) => {
+ return `<div>${props.id}: ${props.name}</div>`;
+ };

const List = () => {
+ const users = getUsers();
return `
<div>
+ ${users.map(user=>User(user)).join('')}
- ${User({id: 1955, name 'Rick Sánchez'})}
- ${User({id: 8765, name 'Beth Harmon'})}
- ${User({id: 7562, name 'Farrokh Bulsara'})}
</div>`;
};

document.getElementById("app").innerHTML = `
${Header()}
${List()}
`;
```

In React, however, the `props` argument is a single parameter: an object to which I can pass whatever I want. Let’s adapt the code.

```diff
import { getUsers } from "./api";
import "./styles.css";

const Header = () => {
return `<h4>Lista de usuarios</h4>`;
};

- const User = (props) => {
+ const User = ({ user }) => {
- return `<div>${props.id}: ${props.name}</div>`;
+ return `<div>${user.id}: ${user.name}</div>`;
};

const List = () => {
const users = getUsers();
return `
<div>
- ${users.map((user) => User(user)).join("")}
+ ${users.map((user) => User({ user })).join("")}
</div>`;
};

document.getElementById("app").innerHTML = `
${Header()}
${List()}
`;
```

### Reactivity

Let’s try to render a random number for each element, calculated at the moment the component is invoked.

```diff
const User = ({ user }) => {
+ const randomNumber = Math.random();
- return `<div>${user.id}: ${user.name}</div>`;
+ return `<div>${user.id}: ${user.name} - ${randomNumber}</div>`;
};
```

If we update it with a setTimeout, we see the value changes in the console, but the interface does not update:

```diff
const User = ({ user }) => {
- const randomNumber = Math.random();
+ let randomNumber = Math.random();
+ setTimeout(() => {
+ randomNumber = Math.random();
+ console.log(randomNumber);
+ }, 3000);
return `<div>${user.id}: ${user.name} - ${randomNumber}</div>`;
};
```

Why doesn’t the interface refresh after the three seconds of the setTimeout? Try to think of the answer...

The explanation is simple: functions are executed only once. At that moment they return something that generates a fragment of HTML. That initial result is what gets injected into the DOM and doesn’t change again, even though the internal logic of the function (like the value of `randomNumber`) does get updated later.

If we look at the console, we see that the value of `randomNumber` is indeed recalculated, but the interface doesn’t reflect that change. This happens because the DOM is not automatically linked to the data of our application.

And this is where libraries like React come in. Their main value is that they incorporate reactivity: they allow us to keep the application state and the user interface in sync.

In React, states are the key piece to persist and manage data. Every time a state changes, React re-executes the components that depend on it, ensuring the interface updates and stays aligned with the most recent information.

### Events and persistence

```diff
const List = () => {
- const users = getUsers();
+ let users = getUsers();

+ const handleClick = () => {
+ alert("button clicked!");
+ users = [...users, { id: 1234, name: "John Doe" }];
+ };

return `
<div>
${users.map((user) => User({ user })).join("")}
+ <button onclick="javascript:handleClick()">Add user</button>
</div>`;
};
```

The button appears but when clicking it, not even the alert shows up. What’s going on?
Again, when `List` is executed, the `handleClick` function is created. However, that function doesn’t run until we click the button, and when that happens, the function no longer exists, because the `List` function has already executed and died.

This is another problem React solves, since it allows us to persist data and functions between executions of our components.

To leave the example ready for the next exercise, let’s make the following change:

```diff
+ export default function App() {
+ return `
+ ${Header()}
+ ${List()}
+ `;
+ }

+ document.getElementById("app").innerHTML = App();
- document.getElementById("app").innerHTML = `
- ${Header()}
- ${List()}
- `;
```
Loading