React
La teoría de operación de React se basa en principios fundamentales que permiten construir interfaces de usuario de forma eficiente y reactiva. A continuación, se presentan los principales conceptos y mecanismos que sustentan el funcionamiento de React.
Teoría de Operación de React
1. Componentes
Los componentes son la base de la arquitectura de React. Permiten dividir la interfaz en partes más pequeñas y reutilizables. Existen dos tipos principales de componentes:
- Componentes Funcionales: Son funciones de JavaScript que retornan elementos de React. Con la introducción de los Hooks, pueden gestionar el estado y los efectos secundarios.
function MiComponente() {
return <div>¡Hola, mundo!</div>;
}
- Componentes de Clase: Usan la sintaxis de clase de JavaScript y pueden tener métodos de ciclo de vida. Aunque todavía son soportados, su uso está disminuyendo en favor de los componentes funcionales.
class MiComponente extends React.Component {
render() {
return <div>¡Hola, mundo!</div>;
}
}
2. JSX (JavaScript XML)
JSX es una sintaxis que permite escribir HTML dentro de archivos de JavaScript. Facilita la creación de elementos de React y hace que el código sea más legible.
const elemento = <h1>Mi Título</h1>;
3. Props (Propiedades)
Las props son un mecanismo para pasar datos de componentes padres a componentes hijos. Son inmutables y ayudan a crear componentes que se pueden reutilizar en diferentes contextos.
function Saludo(props) {
return <h1>¡Hola, {props.nombre}!</h1>;
}
// Uso
<Saludo nombre="Maria" />
4. State (Estado)
El state es un objeto que almacena datos que pueden cambiar a lo largo del ciclo de vida de un componente. Los cambios en el estado activan nuevos renderizados del componente y de sus hijos.
import React, { useState } from 'react';
function Contador() {
const [conteo, setConteo] = useState(0);
return (
<div>
<p>Conteo: {conteo}</p>
<button onClick={() => setConteo(conteo + 1)}>Incrementar</button>
</div>
);
}
5. Ciclo de Vida de los Componentes
Los componentes tienen un ciclo de vida que abarca varias fases, como montaje, actualización y desmontaje. Los componentes de clase tienen métodos específicos (como componentDidMount, componentDidUpdate y componentWillUnmount) que permiten la ejecución de código en diferentes momentos del ciclo de vida. En los componentes funcionales, los Hooks, como useEffect, desempeñan un papel similar.
6. Renderizado
El renderizado en React es un proceso eficiente. Cuando el estado o las props de un componente cambian, React vuelve a renderizar ese componente y sus hijos. React utiliza un algoritmo de reconciliación para determinar qué partes del árbol de componentes necesitan ser actualizadas, minimizando el número de operaciones directas en el DOM.
7. DOM Virtual
React utiliza un concepto llamado DOM Virtual, que es una representación ligera del DOM real. Cuando hay un cambio en el estado o en las props, React realiza una actualización en el DOM Virtual. Luego, compara el DOM Virtual con el DOM real y calcula la diferencia (diffing). Solo las partes que cambiaron se actualizan en el DOM real, lo que mejora el rendimiento.
8. Hooks
Los Hooks son funciones que permiten que los componentes funcionales tengan acceso a recursos de estado y efectos secundarios. Ejemplos de Hooks incluyen useState, useEffect, useContext, entre otros.
import React, { useState, useEffect } from 'react';
function Ejemplo() {
const [contador, setContador] = useState(0);
useEffect(() => {
console.log(`El contador es: ${contador}`);
}, [contador]);
return <button onClick={() => setContador(contador + 1)}>Incrementar</button>;
}
TDD - Vitest (Testing Library)
Las pruebas con Testing Library facilitan la creación de tests desacoplados de la implementación. Simula el comportamiento real del componente y permite usar una interfaz que simula clics y lee contenido de la pantalla de acuerdo con el comportamiento esperado del componente.
// UserManager.test.jsx
import { render, fireEvent, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import UserManager from './UserManager'; // Importando el componente
describe('UserManager', () => {
it('debe permitir al usuario agregar un gerente y mostrarlo en la lista', async () => {
render(<UserManager />);
// Paso 1: Interactuar con el combobox
const input = screen.getByRole('combobox');
fireEvent.change(input, { target: { value: 'Gerente A' } });
// Paso 2: Verificar si aparecen las sugerencias
const suggestion = await screen.findByText('Gerente A');
expect(suggestion).toBeInTheDocument();
// Paso 3: Seleccionar el gerente
fireEvent.click(suggestion);
// Paso 4: Verificar si el gerente seleccionado aparece en la lista
const selectedManager = screen.getByText('Gerente A');
expect(selectedManager).toBeInTheDocument();
});
});