0%
Desarrollo de aplicaciones modernas con React

Desarrollo de aplicaciones modernas con React

Guía completa para crear aplicaciones web eficientes y mantenibles con React.

I

InSkillCoach

· min

Desarrollo de aplicaciones modernas con React

React es una de las bibliotecas de JavaScript más populares para la creación de interfaces de usuario. Desarrollada y mantenida por Facebook (Meta), permite construir aplicaciones web complejas con componentes reutilizables y una gestión eficaz del estado.

¿Por qué elegir React?

  • Enfoque declarativo: Usted describe cómo debería verse su interfaz y React se encarga de las actualizaciones
  • Basado en componentes: Cree elementos de interfaz encapsulados y reutilizables
  • Ecosistema rico: Una amplia variedad de bibliotecas y herramientas complementarias
  • Gran comunidad: Soporte, recursos y actualizaciones periódicas
  • Rendimiento optimizado: Virtual DOM y reconciliación para actualizaciones eficientes
  • Adoptado por grandes empresas: Facebook, Instagram, Netflix, Airbnb, etc.

Puesta en marcha de un proyecto React

Creación con Create React App

Create React App es una herramienta oficial que permite iniciar rápidamente un proyecto React:

# Instalación
npx create-react-app mon-application

# Inicio
cd mon-application
npm start

Uso de Vite (alternativa moderna)

Vite ofrece tiempos de compilación más rápidos y una mejor experiencia de desarrollo:

# Instalación
npm create vite@latest mon-application -- --template react

# Inicio
cd mon-application
npm install
npm run dev

Los fundamentos de React

Componentes

Los componentes son los bloques básicos de una aplicación React:

// Componente funcional
function Salutation(props) {
  return <h1>Bonjour, {props.nom} !</h1>;
}

// Uso
<Salutation nom="Alice" />

JSX

JSX es una extensión de sintaxis que permite escribir HTML dentro de JavaScript:

const element = <h1>Bonjour, monde !</h1>;

// Con expresiones JavaScript
const nom = "Alice";
const element = <h1>Bonjour, {nom} !</h1>;

// Con atributos
const element = <img src={user.avatarUrl} alt="Avatar" />;

// Elementos anidados
const element = (
  <div>
    <h1>Titre</h1>
    <p>Paragraphe</p>
  </div>
);

Props

Las props permiten pasar datos de un componente padre a un componente hijo:

// Definición del componente
function Carte(props) {
  return (
    <div className="carte">
      <h2>{props.titre}</h2>
      <p>{props.description}</p>
      {props.children}
    </div>
  );
}

// Uso
<Carte 
  titre="Mon titre" 
  description="Ma description"
>
  <button>En savoir plus</button>
</Carte>

Estado (State)

El estado permite almacenar datos que pueden cambiar con el tiempo:

import { useState } from 'react';

function Compteur() {
  // Declaración de un estado
  const [compteur, setCompteur] = useState(0);
  
  return (
    <div>
      <p>Vous avez cliqué {compteur} fois</p>
      <button onClick={() => setCompteur(compteur + 1)}>
        Cliquez ici
      </button>
    </div>
  );
}

Ciclo de vida con Hooks

Los Hooks permiten usar el estado y otras funcionalidades de React en los componentes funcionales:

import { useState, useEffect } from 'react';

function ExempleEffet() {
  const [compteur, setCompteur] = useState(0);
  
  // Similar a componentDidMount y componentDidUpdate
  useEffect(() => {
    // Actualiza el título del documento
    document.title = `Vous avez cliqué ${compteur} fois`;
    
    // Función de limpieza (similar a componentWillUnmount)
    return () => {
      document.title = 'React App';
    };
  }, [compteur]); // Se ejecuta únicamente si compteur cambia
  
  return (
    <div>
      <p>Vous avez cliqué {compteur} fois</p>
      <button onClick={() => setCompteur(compteur + 1)}>
        Cliquez ici
      </button>
    </div>
  );
}

Gestión de eventos

React utiliza una sintaxis similar a HTML para gestionar los eventos:

function Bouton() {
  function handleClick(e) {
    e.preventDefault();
    console.log('Le bouton a été cliqué');
  }
  
  return (
    <button onClick={handleClick}>
      Cliquez ici
    </button>
  );
}

Renderizado condicional

Puede mostrar distintos elementos en función de condiciones:

function Connexion(props) {
  const estConnecte = props.estConnecte;
  
  return (
    <div>
      {estConnecte ? (
        <BoutonDeconnexion />
      ) : (
        <BoutonConnexion />
      )}
    </div>
  );
}

// Otro enfoque
function Message(props) {
  const nonLu = props.messagesNonLus.length;
  
  return (
    <div>
      <h1>Bonjour !</h1>
      {nonLu > 0 && (
        <p>Vous avez {nonLu} message(s) non lu(s).</p>
      )}
    </div>
  );
}

Listas y claves

Para mostrar listas de elementos, utilice map() y claves únicas:

function ListeArticles(props) {
  const articles = props.articles;
  
  return (
    <ul>
      {articles.map((article) => (
        <li key={article.id}>
          {article.titre}
        </li>
      ))}
    </ul>
  );
}

Gestión avanzada del estado

Context API

La Context API permite compartir datos entre componentes sin pasar por las props:

// Creación del contexto
const ThemeContext = React.createContext('light');

// Proveedor de contexto
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

// Consumo del contexto con useContext
function Bouton() {
  const theme = useContext(ThemeContext);
  
  return (
    <button className={theme}>
      Je suis stylisé selon le thème {theme}
    </button>
  );
}

useReducer para una gestión de estado compleja

useReducer es preferible a useState para estados complejos:

import { useReducer } from 'react';

// Definición del reducer
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { compteur: state.compteur + 1 };
    case 'decrement':
      return { compteur: state.compteur - 1 };
    default:
      throw new Error();
  }
}

function Compteur() {
  // Uso del reducer
  const [state, dispatch] = useReducer(reducer, { compteur: 0 });
  
  return (
    <div>
      Compteur: {state.compteur}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

Bibliotecas de gestión de estado

Para aplicaciones más complejas, puede utilizar bibliotecas específicas:

Redux

// Actions
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// Action creators
function increment() {
  return { type: INCREMENT };
}

// Reducer
function compteurReducer(state = { valeur: 0 }, action) {
  switch (action.type) {
    case INCREMENT:
      return { valeur: state.valeur + 1 };
    case DECREMENT:
      return { valeur: state.valeur - 1 };
    default:
      return state;
  }
}

// Store
const store = createStore(compteurReducer);

// Componente conectado
function Compteur({ valeur, increment, decrement }) {
  return (
    <div>
      <span>{valeur}</span>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

const mapStateToProps = state => ({
  valeur: state.valeur
});

const mapDispatchToProps = {
  increment,
  decrement
};

export default connect(mapStateToProps, mapDispatchToProps)(Compteur);

Zustand (alternativa moderna)

import create from 'zustand';

// Creación del store
const useStore = create(set => ({
  compteur: 0,
  increment: () => set(state => ({ compteur: state.compteur + 1 })),
  decrement: () => set(state => ({ compteur: state.compteur - 1 })),
}));

// Uso en un componente
function Compteur() {
  const { compteur, increment, decrement } = useStore();
  
  return (
    <div>
      <span>{compteur}</span>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

Enrutamiento con React Router

React Router permite gestionar la navegación en una aplicación React:

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Accueil</Link>
        <Link to="/a-propos">À propos</Link>
        <Link to="/contact">Contact</Link>
      </nav>
      
      <Routes>
        <Route path="/" element={<Accueil />} />
        <Route path="/a-propos" element={<APropos />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/produits/:id" element={<DetailProduit />} />
        <Route path="*" element={<PageNonTrouvee />} />
      </Routes>
    </BrowserRouter>
  );
}

// Acceso a los parámetros de la URL
import { useParams } from 'react-router-dom';

function DetailProduit() {
  const { id } = useParams();
  
  return <h1>Détail du produit {id}</h1>;
}

Formularios en React

Formularios controlados

En un formulario controlado, React gestiona el estado del formulario:

import { useState } from 'react';

function FormulaireConnexion() {
  const [email, setEmail] = useState('');
  const [motDePasse, setMotDePasse] = useState('');
  
  function handleSubmit(e) {
    e.preventDefault();
    console.log('Email:', email);
    console.log('Mot de passe:', motDePasse);
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Email:
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            required
          />
        </label>
      </div>
      <div>
        <label>
          Mot de passe:
          <input
            type="password"
            value={motDePasse}
            onChange={(e) => setMotDePasse(e.target.value)}
            required
          />
        </label>
      </div>
      <button type="submit">Se connecter</button>
    </form>
  );
}

Bibliotecas de formularios

Para formularios complejos, utilice bibliotecas como Formik o React Hook Form:

// Con React Hook Form
import { useForm } from 'react-hook-form';

function FormulaireInscription() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  const onSubmit = data => console.log(data);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>Nom</label>
        <input {...register('nom', { required: 'Le nom est requis' })} />
        {errors.nom && <p>{errors.nom.message}</p>}
      </div>
      
      <div>
        <label>Email</label>
        <input 
          {...register('email', { 
            required: 'L\'email est requis',
            pattern: {
              value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
              message: 'Adresse email invalide'
            }
          })} 
        />
        {errors.email && <p>{errors.email.message}</p>}
      </div>
      
      <button type="submit">S'inscrire</button>
    </form>
  );
}

Optimización del rendimiento

React.memo

React.memo permite evitar renderizados innecesarios de los componentes funcionales:

const MonComposant = React.memo(function MonComposant(props) {
  // Su componente
});

useMemo y useCallback

Estos hooks permiten memorizar valores y funciones:

import { useMemo, useCallback } from 'react';

function ExempleOptimisation({ a, b }) {
  // Memoriza el resultado del cálculo
  const resultat = useMemo(() => {
    console.log('Calcul coûteux...');
    return a * b;
  }, [a, b]); // Recalcula únicamente si a o b cambian
  
  // Memoriza la función
  const handleClick = useCallback(() => {
    console.log('Bouton cliqué avec résultat:', resultat);
  }, [resultat]); // Se vuelve a crear únicamente si resultat cambia
  
  return (
    <div>
      <p>Résultat: {resultat}</p>
      <button onClick={handleClick}>Cliquer</button>
    </div>
  );
}

Lazy Loading

La carga diferida permite dividir su aplicación en fragmentos más pequeños:

import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

// Carga diferida de los componentes
const Accueil = lazy(() => import('./pages/Accueil'));
const APropos = lazy(() => import('./pages/APropos'));
const Contact = lazy(() => import('./pages/Contact'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Chargement...</div>}>
        <Routes>
          <Route path="/" element={<Accueil />} />
          <Route path="/a-propos" element={<APropos />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

Tests en React

Tests unitarios con Jest y React Testing Library

// Componente que se va a probar
function Salutation({ nom }) {
  return <h1>Bonjour, {nom} !</h1>;
}

// Test
import { render, screen } from '@testing-library/react';
import Salutation from './Salutation';

test('affiche le message de salutation', () => {
  render(<Salutation nom="Alice" />);
  const element = screen.getByText(/bonjour, alice !/i);
  expect(element).toBeInTheDocument();
});

Tests de interacción

import { render, screen, fireEvent } from '@testing-library/react';
import Compteur from './Compteur';

test('incrémente le compteur lorsque le bouton est cliqué', () => {
  render(<Compteur />);
  
  // Comprobar el valor inicial
  expect(screen.getByText(/compteur: 0/i)).toBeInTheDocument();
  
  // Hacer clic en el botón
  fireEvent.click(screen.getByText('+'));
  
  // Comprobar el nuevo valor
  expect(screen.getByText(/compteur: 1/i)).toBeInTheDocument();
});

Despliegue de una aplicación React

Build de producción

# Con Create React App
npm run build

# Con Vite
npm run build

Alojamiento estático

Puede desplegar su aplicación en plataformas como:

  • Netlify: Arrastre y suelte la carpeta build o configure un despliegue continuo
  • Vercel: Optimizado para aplicaciones React, con despliegue automático desde GitHub
  • GitHub Pages: Ideal para proyectos personales o de código abierto
  • Firebase Hosting: Solución completa con autenticación y base de datos

Buenas prácticas

  1. Estructure su proyecto: Organice sus archivos por funcionalidad o por tipo
  2. Utilice componentes funcionales: Más sencillos y con mejor rendimiento gracias a los Hooks
  3. Evite el props drilling: Utilice Context o una biblioteca de gestión de estado
  4. Escriba tests: Asegúrese de que su aplicación funciona como se espera
  5. Optimice el rendimiento: Utilice React.memo, useMemo y useCallback con criterio
  6. Siga los principios SOLID: Cree componentes con una única responsabilidad
  7. Utilice TypeScript: Añada tipado estático para evitar errores
  8. Documente sus componentes: Utilice herramientas como Storybook

Conclusión

React es una biblioteca potente que permite crear interfaces de usuario modernas y de alto rendimiento. Su flexibilidad y su rico ecosistema la convierten en una excelente opción para el desarrollo de aplicaciones web de cualquier tamaño.

Si dominas los conceptos fundamentales y las buenas prácticas que se presentan en este artículo, serás capaz de crear aplicaciones React robustas, mantenibles y escalables.

InSkillCoach

Acerca de InSkillCoach

Experto en formación y tecnologías

Coach especializado en tecnologías avanzadas e IA, impulsado por GNeurone Inc.

Certificaciones:

  • AWS Certified Solutions Architect – Professional
  • Certificaciones de Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
670
163

Comentarios

Los comentarios funcionan con GitHub Discussions

Inicia sesión con GitHub para participar en la discusión

¡Enlace copiado!