Introducción a React
1. ¿Qué es React?
React es una biblioteca de JavaScript desarrollada por Facebook para construir interfaces de usuario. Se enfoca en la creación de componentes reutilizables y eficientes que permiten el desarrollo de aplicaciones web rápidas y escalables.
Características clave de React:
Componentes: React basa su arquitectura en componentes. Cada componente es una pieza reutilizable de código que puede manejar su propio estado y lógica.
Virtual DOM: React utiliza un DOM virtual para actualizar solo las partes que cambian, lo que mejora significativamente el rendimiento.
Unidirectional Data Flow (Flujo de Datos Unidireccional): En React, los datos fluyen en una sola dirección, desde el componente padre hacia los componentes hijos.
JSX: Un lenguaje similar a HTML que permite combinar la estructura del componente con lógica JavaScript.
2. Evolución de React: De create-react-app a Vite
React con create-react-app (Antes).
Antes de la aparición de herramientas como Vite, React se inicializaba principalmente usando create-react-app (CRA). CRA es un generador de proyectos que proporciona una configuración completa para desarrollar aplicaciones React sin necesidad de configuraciones manuales con Webpack o Babel.
npx create-react-app my-app
cd my-app
npm start
Con estos comandos, podías crear un proyecto React con CRA y ejecutarlo en un servidor de desarrollo. Sin embargo, CRA tiene algunas desventajas que han llevado a la adopción de herramientas más modernas como Vite.
Desventajas de create-react-app:
Lentitud: A medida que las aplicaciones crecen, CRA puede volverse lento durante el tiempo de compilación y recarga en caliente.
Sobrecarga de configuración: Aunque CRA oculta la configuración compleja, esta puede ser difícil de personalizar cuando el proyecto lo requiere.
React con Vite (Ahora)
Vite es una herramienta de desarrollo moderna que mejora significativamente los tiempos de desarrollo y la experiencia del programador, superando a CRA en términos de velocidad y simplicidad.
Ventajas de Vite:
Velocidad: Vite es extremadamente rápido, incluso en proyectos grandes, debido a su compilación basada en ES Modules (módulos de ECMAScript).
Recarga en caliente instantánea: Vite ofrece Hot Module Replacement (HMR), que recarga solo los módulos que cambian, proporcionando un entorno de desarrollo mucho más ágil.
Configuración ligera: La configuración es mínima y fácil de personalizar cuando es necesario.
Crear un proyecto React con Vite:
Hoy en día, los desarrolladores de React utilizan Vite para crear proyectos mucho más rápido. Aquí te mostramos cómo hacerlo.
npm create vite@latest .
Con esta sencilla línea de comandos, puedes crear un proyecto React con Vite y comenzar a desarrollar aplicaciones web modernas de forma rápida y eficiente.
Nota: Al ejecutar el comando anterior en tu terminal, se abrirá un asistente para configurar tu proyecto con Vite. Puedes elegir entre diferentes plantillas, incluyendo React, Vue, Preact y más. De la misma forma la forma en la que puedes programar ya que es posible utilizar javascrit o typescript.
npm install
npm run dev
Con los comandos anteriores, puedes instalar las dependencias y ejecutar el servidor de desarrollo de Vite para comenzar a trabajar en tu proyecto React.
3. Conceptos Básicos de React
Antes de iniciar con React es necesario conocer un poco la estructura básica de un proyecto en React, los componentes, JSX, props, estado y hooks.
Por ahora lo más importante es mantener un orden que quizás al principio no se entienda pero con el tiempo se irá aclarando.
Para ello vamos a crear una directorio llamado components y dentro del directorio src vamos a crear un archivo llamado Gretting.jsx.
JSX: Es una extensión de JavaScript que permite escribir HTML en archivos JavaScript.
function Greeting() {
return <h1>¡Hola, mundo!</h1>;
}
export default Greeting;
3.1. Componentes en React
Los componentes son bloques reutilizables que contienen lógica, estructura y estilo. En React, un componente puede ser:
Funcional: Es el enfoque moderno en React. Son componentes escritos como funciones de JavaScript.
De clase: Son el enfoque anterior, basados en la programación orientada a objetos. Aún se usan en proyectos más antiguos.
En la sección anterior, creamos un componente funcional llamado Greeting. Ahora, vamos a importar y usar este componente en el archivo App.js.
import Greeting from './components/Greeting';
function App() {
return (
<div>
<Greeting />
</div>
;
)
}
export default App;
Para correr el proyecto ejecutamos el comando:
npm run dev
3.2. JSX: JavaScript + HTML
JSX es una extensión de JavaScript que permite escribir HTML dentro de archivos JavaScript. Esto facilita la creación de componentes y mejora la legibilidad del código.
<h1>¡Hola, mundo!</h1>
JSX se compila a llamadas de funciones de React que crean elementos de React.
Por ejemplo, el código JSX anterior se compila a:
.createElement('h1', null, '¡Hola, mundo!'); React
Sin embargo no es necesario preocuparse por esto ya que React se encarga de hacerlo por nosotros.
Nota: Los elementos JSX deben tener un solo contenedor raíz. Si necesitas devolver varios elementos, puedes envolverlos en un contenedor div o usar Fragment.
Ejemplo de Fragment:
function App() {
return (
<>
<h1>¡Hola, mundo!</h1>
<p>Bienvenido a mi aplicación.</p>
</>
;
) }
En el ejemplo anterior, usamos Fragment para envolver múltiples elementos sin necesidad de un contenedor adicional.
Para poder probar este ejemplo es necesario modificar el archivo App.js. y correr el servidor de desarrollo.
npm run dev
3.3. Props y Estado
Props: Son los “argumentos” que los componentes reciben para configurar su contenido o comportamiento.
Para entender mejor cómo funcionan las props, vamos a modificar el componente Greeting para que reciba un prop llamado name.
En el directorio components, modificamos el archivo llamado Greeting.jsx con el siguiente contenido:
export default function Greeting(props) {
return <h1>¡Hola, {props.name}!</h1>;
}
Muy bien ahora vamos a modificar el archivo App.js para que el componente Greeting reciba el prop name.
import Greeting from './components/Greeting';
function App() {
return (
<>
<Greeting name="Diego" />
</>
;
)
}
export default App;
En el ejemplo anterior, pasamos el prop name con el valor “Diego” al componente Greeting. Esto permite personalizar el saludo que se muestra en la pantalla.
3.4. Hooks
Los hooks fueron introducidos en React 16.8 y son funciones que permiten a los componentes funcionales gestionar el estado y otros efectos del ciclo de vida, funcionalidades que anteriormente solo estaban disponibles en los componentes de clase.
useState: Gestiona el estado dentro de un componente funcional.
useEffect: Maneja efectos secundarios, como llamadas a APIs o actualizaciones del DOM.
Ejemplo con useState y useEffect:
import { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Has hecho clic ${count} veces`;
, [count]); // Se ejecuta cada vez que 'count' cambia
}
return (
<div>
<p>Has hecho clic {count} veces</p>
<button onClick={() => setCount(count + 1)}>Haz clic</button>
</div>
;
)
}
export default App;
En el código anterior, usamos useState para inicializar el estado count en 0 y setCount para actualizarlo. También usamos useEffect para actualizar el título de la página cada vez que count cambia.
Para entender mejor este concepto vamo a crear un nuevo componente llamado Clasificador de Edades.
En el directorio components, creamos un archivo llamado AgeClassifier.jsx con el siguiente contenido:
import { useState } from 'react';
export default function AgeClassifier() {
const [age, setAge] = useState(0);
const [classification, setClassification] = useState('');
function classifyAge() {
if (age < 18) {
setClassification('Menor de edad');
else {
} setClassification('Mayor de edad');
}
}
return (
<div>
<input
="number"
type={age}
value={(e) => setAge(parseInt(e.target.value))}
onChange/>
<button onClick={classifyAge}>Clasificar Edad</button>
<p>{classification}</p>
</div>
;
) }
En el código anterior, usamos useState para inicializar el estado age en 0 y classification en una cadena vacía. Luego, definimos una función classifyAge que clasifica la edad en “Menor de edad” o “Mayor de edad” según el valor de age. Finalmente, mostramos un campo de entrada para la edad, un botón para clasificarla y un mensaje con la clasificación.
Para probar este componente, vamos a importarlo y usarlo en el archivo App.js.
import AgeClassifier from './components/AgeClassifier';
function App() {
return (
<>
<AgeClassifier />
</>
;
)
}
export default App;
Ahora, al correr el servidor de desarrollo, podrás ver el componente AgeClassifier en acción.
npm run dev
Con este ejercicio hemos aprendido a usar los hooks useState y useEffect en un componente funcional de React. Estos hooks son fundamentales para gestionar el estado y los efectos secundarios en aplicaciones React modernas.
4. Diferencias entre el Uso Antiguo y el Actual de React
Antes: Componentes de Clase
En versiones anteriores, los desarrolladores usaban componentes de clase para manejar el estado y el ciclo de vida de los componentes.
class Greeting extends React.Component {
render() {
return <h1>¡Hola, {this.props.name}!</h1>;
} }
Ahora: Componentes Funcionales con Hooks
Hoy en día, la norma es usar componentes funcionales con hooks, ya que son más concisos y fáciles de trabajar.
function Greeting({ name }) {
return <h1>¡Hola, {name}!</h1>;
}
Ventajas del enfoque moderno con Hooks:
Menos código: Los componentes funcionales con hooks son más cortos y claros.
Manejo de estado más simple: useState y otros hooks ofrecen una forma directa y sencilla de gestionar el estado y el ciclo de vida.
Mejor rendimiento: React puede optimizar mejor los componentes funcionales.
Microproyecto con React
Para finalizar este módulo vamos a crear un microproyecto con React y Vite. En este proyecto vamos a crear una aplicación de lista de tareas (To-Do List) que permita agregar, eliminar y marcar tareas como completadas.
1. Crear un Proyecto con Vite
Para comenzar, vamos a crear un nuevo proyecto React con Vite. Abre tu terminal y ejecuta el siguiente comando:
npm create vite@latest todo-list
cd todo-list
npm install
Este comando creará un nuevo proyecto React con Vite llamado todo-list y lo instalará en tu directorio actual.
2. Crear Componentes
En el directorio src/components, crea un nuevo archivo llamado TodoList.jsx con el siguiente contenido:
import { useState } from 'react';
export default function TodoList() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');
function addTask() {
if (newTask.trim() !== '') {
setTasks([...tasks, { id: tasks.length + 1, text: newTask, completed: false }]);
setNewTask('');
}
}
function deleteTask(id) {
setTasks(tasks.filter((task) => task.id !== id));
}
function toggleTask(id) {
setTasks(tasks.map((task) => {
if (task.id === id) {
return { ...task, completed: !task.completed };
}return task;
;
}))
}
return (
<div>
<h1>Lista de Tareas</h1>
<input
="text"
type={newTask}
value={(e) => setNewTask(e.target.value)}
onChange="Nueva tarea"
placeholder/>
<button onClick={addTask}>Agregar Tarea</button>
<ul>
.map((task) => (
{tasks<li key={task.id}>
<input
="checkbox"
type={task.completed}
checked={() => toggleTask(task.id)}
onChange/>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
.text}
{task</span>
<button onClick={() => deleteTask(task.id)}>Eliminar</button>
</li>
))}</ul>
</div>
;
) }
En el código anterior, creamos un componente funcional TodoList que gestiona una lista de tareas. Usamos el hook useState para mantener el estado de las tareas y la nueva tarea que se está escribiendo. También definimos funciones para agregar, eliminar y marcar tareas como completadas.
3. Usar el Componente TodoList
En el archivo src/App.js, importa y usa el componente TodoList que acabamos de crear:
import TodoList from './components/TodoList';
function App() {
return (
<div>
<TodoList />
</div>
;
)
}
export default App;
4. Ejecutar el Proyecto
Finalmente, ejecuta el servidor de desarrollo para ver tu aplicación de lista de tareas en acción:
npm run dev
Con estos pasos, has creado una aplicación de lista de tareas funcional con React y Vite. Puedes agregar, eliminar y marcar tareas como completadas, demostrando cómo los componentes, el estado y los hooks de React trabajan juntos para crear aplicaciones web interactivas y dinámicas.
Reto
Mejorar la aplicación de lista de tareas agregando las siguientes funcionalidades:
Editar Tareas: Permite editar el texto de una tarea existente.
Filtrar Tareas: Agrega botones para filtrar las tareas por estado (completadas, pendientes, todas).
Guardar Tareas: Implementa la capacidad de guardar las tareas en el almacenamiento local del navegador para que persistan entre sesiones.
Estilos Personalizados: Añade estilos CSS personalizados para mejorar la apariencia de la aplicación.
🔍 Solución
Para implementar estas funcionalidades, puedes seguir los siguientes pasos:
- Editar Tareas: Agrega un botón de edición a cada tarea que permita cambiar su texto.
function editTask(id, text) {
const updatedText = prompt('Editar tarea:', text);
if (updatedText !== null) {
setTasks(tasks.map((task) => {
if (task.id === id) {
return { ...task, text: updatedText };
}return task;
;
}))
} }
- Filtrar Tareas: Agrega botones para filtrar las tareas por estado.
function filterTasks(status) {
switch (status) {
case 'completed':
return tasks.filter((task) => task.completed);
case 'pending':
return tasks.filter((task) => !task.completed);
default:
return tasks;
} }
- Guardar Tareas: Utiliza el almacenamiento local del navegador para guardar las tareas.
useEffect(() => {
const savedTasks = JSON.parse(localStorage.getItem('tasks'));
if (savedTasks) {
setTasks(savedTasks);
}, []);
}
useEffect(() => {
.setItem('tasks', JSON.stringify(tasks));
localStorage, [tasks]); }
El archivo TodoList.jsx completo con estas mejoras se vería así:
import { useState, useEffect } from 'react';
export default function TodoList() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');
useEffect(() => {
const savedTasks = JSON.parse(localStorage.getItem('tasks'));
if (savedTasks) {
setTasks(savedTasks);
}, []);
}
useEffect(() => {
.setItem('tasks', JSON.stringify(tasks));
localStorage, [tasks]);
}
function addTask() {
if (newTask.trim() !== '') {
setTasks([...tasks, { id: tasks.length + 1, text: newTask, completed: false }]);
setNewTask('');
}
}
function deleteTask(id) {
setTasks(tasks.filter((task) => task.id !== id));
}
function toggleTask(id) {
setTasks(tasks.map((task) => {
if (task.id === id) {
return { ...task, completed: !task.completed };
}return task;
;
}))
}
function editTask(id, text) {
const updatedText = prompt('Editar tarea:', text);
if (updatedText !== null) {
setTasks(tasks.map((task) => {
if (task.id === id) {
return { ...task, text: updatedText };
}return task;
;
}))
}
}
function filterTasks(status) {
switch (status) {
case 'completed':
return tasks.filter((task) => task.completed);
case 'pending':
return tasks.filter((task) => !task.completed);
default:
return tasks;
}
}
return (
<div>
<h1>Lista de Tareas</h1>
<input
="text"
type={newTask}
value={(e) => setNewTask(e.target.value)}
onChange="Nueva tarea"
placeholder/>
<button onClick={addTask}>Agregar Tarea</button>
<ul>
filterTasks('all').map((task) => (
{<li key={task.id}>
<input
="checkbox"
type={task.completed}
checked={() => toggleTask(task.id)}
onChange/>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
.text}
{task</span>
<button onClick={() => editTask(task.id, task.text)}>
Editar</button>
<button onClick={() => deleteTask(task.id)}>
Eliminar</button>
</li>
))}</ul>
<div>
<button onClick={() => setTasks(filterTasks('all'))}>
Todas</button>
<button onClick={() => setTasks(filterTasks('completed'))}>
Completadas</button>
<button onClick={() => setTasks(filterTasks('pending'))}>
Pendientes</button>
</div>
</div>
;
) }
- Estilos Personalizados: Crea un archivo CSS en el directorio src y agrega estilos personalizados.
body {font-family: Arial, sans-serif;
}
button {padding: 0.5rem 1rem;
margin: 0.5rem;
cursor: pointer;
}
li {display: flex;
align-items: center;
margin: 0.5rem 0;
}
[type="checkbox"] {
inputmargin-right: 1rem;
}
span {flex: 1;
}
button {background-color: #f44336;
color: white;
border: none;
border-radius: 4px;
}
:hover {
buttonbackground-color: #d32f2f;
}
:active {
buttonbackground-color: #b71c1c;
}
[type="text"] {
inputpadding: 0.5rem;
margin-right: 1rem;
}
[type="checkbox"] {
inputtransform: scale(1.5);
}
ul {list-style-type: none;
padding: 0;
}
h1 {text-align: center;
}
.add {
buttonbackground-color: #4caf50;
}
.add:hover {
buttonbackground-color: #388e3c;
}
.add:active {
buttonbackground-color: #2e7d32;
}
.edit {
buttonbackground-color: #2196f3;
}
.edit:hover {
buttonbackground-color: #1e88e5;
}
.edit:active {
buttonbackground-color: #1976d2;
}
.delete {
buttonbackground-color: #f44336;
}
.delete:hover {
buttonbackground-color: #d32f2f;
}
.delete:active {
buttonbackground-color: #b71c1c;
}
.filter {
buttonbackground-color: #9e9e9e;
}
.filter:hover {
buttonbackground-color: #757575;
}
.filter:active {
buttonbackground-color: #424242;
}
.clear {
buttonbackground-color: #f44336;
}
.clear:hover {
buttonbackground-color: #d32f2f;
}
.clear:active {
buttonbackground-color: #b71c1c;
}
.save {
buttonbackground-color: #4caf50;
}
.save:hover {
buttonbackground-color: #388e3c;
}
.save:active {
buttonbackground-color: #2e7d32;
}
.cancel {
buttonbackground-color: #f44336;
}
.cancel:hover {
buttonbackground-color: #d32f2f;
}
.cancel:active {
buttonbackground-color: #b71c1c;
}
.toggle {
buttonbackground-color: #4caf50;
}
.toggle:hover {
buttonbackground-color: #388e3c;
}
.toggle:active {
buttonbackground-color: #2e7d32;
}
.toggle-all {
buttonbackground-color: #9e9e9e;
}
.toggle-all:hover {
buttonbackground-color: #757575;
}
.toggle-all:active {
buttonbackground-color: #424242;
}
.clear-completed {
buttonbackground-color: #f44336;
}
.clear-completed:hover {
buttonbackground-color: #d32f2f;
}
.clear-completed:active {
buttonbackground-color: #b71c1c;
}
.clear-all {
buttonbackground-color: #f44336;
}
.clear-all:hover {
buttonbackground-color: #d32f2f;
}
.clear-all:active {
buttonbackground-color: #b71c1c;
}
.save-all {
buttonbackground-color: #4caf50;
}
.save-all:hover {
buttonbackground-color: #388e3c;
}
.save-all:active {
buttonbackground-color: #2e7d32;
}
.cancel-all {
buttonbackground-color: #f44336;
}
.cancel-all:hover {
buttonbackground-color: #d32f2f;
}
.cancel-all:active {
buttonbackground-color: #b71c1c;
}
.filter-all {
buttonbackground-color: #9e9e9e;
}
.filter-all:hover {
buttonbackground-color: #757575;
}
.filter-all:active {
buttonbackground-color: #424242;
}
.filter-completed {
buttonbackground-color: #9e9e9e;
}
.filter-completed:hover {
buttonbackground-color: #757575;
}
.filter-completed:active {
buttonbackground-color: #424242;
}
.filter-pending {
buttonbackground-color: #9e9e9e;
}
.filter-pending:hover {
buttonbackground-color: #757575;
}
.filter-pending:active {
buttonbackground-color: #424242;
}
.filter-clear {
buttonbackground-color: #f44336;
}
.filter-clear:hover {
buttonbackground-color: #d32f2f;
}
.filter-clear:active {
buttonbackground-color: #b71c1c;
}
.filter-save {
buttonbackground-color: #4caf50;
}
.filter-save:hover {
buttonbackground-color: #388e3c;
}
.filter-save:active {
buttonbackground-color: #2e7d32;
}
.filter-cancel {
buttonbackground-color: #f44336;
}
.filter-cancel:hover {
buttonbackground-color: #d32f2f;
}
.filter-cancel:active {
buttonbackground-color: #b71c1c;
}
.filter-toggle {
buttonbackground-color: #4caf50;
}
.filter-toggle:hover {
buttonbackground-color: #388e3c;
}
.filter-toggle:active {
buttonbackground-color: #2e7d32;
}
.filter-toggle-all {
buttonbackground-color: #9e9e9e;
}
.filter-toggle-all:hover {
buttonbackground-color: #757575;
}
.filter-toggle-all:active {
buttonbackground-color: #424242;
}
.filter-clear-completed {
buttonbackground-color: #f44336;
}
.filter-clear-completed:hover {
buttonbackground-color: #d32f2f;
}
.filter-clear-completed:active {
buttonbackground-color: #b71c1c;
}
.filter-clear-all {
buttonbackground-color: #f44336;
}
.filter-clear-all:hover {
buttonbackground-color: #d32f2f;
}
.filter-clear-all:active {
buttonbackground-color: #b71c1c;
}
.filter-save-all {
buttonbackground-color: #4caf50;
}
.filter-save-all:hover {
buttonbackground-color: #388e3c;
}
.filter-save-all:active {
buttonbackground-color: #2e7d32;
}
.filter-cancel-all {
buttonbackground-color: #f44336;
}
.filter-cancel-all:hover {
buttonbackground-color: #d32f2f;
}
.filter-cancel-all:active {
buttonbackground-color: #b71c1c;
}
.filter-all-all {
buttonbackground-color: #9e9e9e;
}
.filter-all-all:hover {
buttonbackground-color: #757575;
}
.filter-all-all:active {
buttonbackground-color: #424242;
}
.filter-completed-completed {
buttonbackground-color: #9e9e9e;
}
.filter-completed-completed:hover {
buttonbackground-color: #757575;
}
.filter-completed-completed:active {
buttonbackground-color: #424242;
}
.filter-pending-pending {
buttonbackground-color: #9e9e9e;
}
.filter-pending-pending:hover {
buttonbackground-color: #757575;
}
.filter-pending-pending:active {
buttonbackground-color: #424242;
}
.filter-clear-clear {
buttonbackground-color: #f44336;
}
Con estas mejoras, tu aplicación de lista de tareas será más interactiva, funcional y atractiva visualmente. ¡Sigue experimentando y mejorando tus habilidades con React!
Conclusión: React Antes y Ahora con Vite
React ha evolucionado significativamente desde sus inicios, pasando de componentes de clase y callbacks a componentes funcionales y hooks. La introducción de Vite ha mejorado aún más la experiencia de desarrollo al proporcionar una configuración ligera y un rendimiento excepcional.