Saltar al contenido
Building a React Data Grid CRUD Admin App 30 Minutes

Building a React Data Grid CRUD Admin App 30 Minutes

Resumen; DR Si has creado una app CRUD de administrador antes, conoces la rutina: una cuadrícula casi correcta, un formulario modal a medio terminar, una nota adhesiva de "editaremos filas más tarde" y tres semanas de tickets de "el filtro no funciona en columnas de fecha". Reconstruí la clásica consola de administración de Northwind en menos de 30 minutos — CRUD completo en [...]

11 min read

TL;DR

Si has creado una aplicación CRUD de administrador antes, conoces la rutina: una cuadrícula casi correcta, un formulario modal a medio terminar, una nota adhesiva de "editaremos filas más tarde" y tres semanas de tickets de "el filtro no funciona en las columnas de fechas".

Reconstruí la clásica consola de administración de Northwind en menos de 30 minutos — CRUD completo en pedidos, clientes, productos, remitentes y comerciales — usando la Ignite UI React Data Grid para la interfaz y una pequeña API SQLite Core de 10 + EF para el backend. Código total de la interfaz: unas 1.500 líneas de TypeScript. Tiempo total luchando contra la cuadrícula: ~0 minutos.

Si estás evaluando una React Data Grid para una aplicación de administración real, este es el caso de uso que importa: edición en línea, filtrado, desplegables relacionales, validación, detalle maestro, resúmenes y temáticas que se mantienen unidas una vez que la página deja de ser un juguete.

Repo: react-grids/react-data-grids-crud

React aplicación Data Grid CRUD que muestra edición en línea con un desplegable para remitentes en Ignite UI for React

Esa es la captura de pantalla que quiero que te lleves. Pasa el cursor → cualquier fila una tira de acción se desliza con Editar y Eliminar. Haz clic en Editar → la fila se puede editar en línea, aparecen los chips de guardar/cancelar. Haz clic en el desplegable → una combinación de búsqueda mientras escribes con encabezados agrupados. Selecciona una fila → se abre un panel de detalle maestro debajo con los datos unidos.

Eso no es una construcción personalizada. Eso es<IgrGrid rowEditable> un plus<IgrActionStrip><IgrGridEditingActions /></IgrActionStrip>. En un minuto llegaremos al código.

Las demos CRUD son fáciles. Las aplicaciones CRUD no lo son.

Las aplicaciones internas de administración están por todas partes. Todas las empresas los tienen. Nunca llegan a la demo reel. Y sin embargo — línea por línea — son de las interfaces más difíciles que puedes construir, porque los usuarios las usan a diario y notan cada borde áspero.

Una página CRUD real necesita:

  • Ordenar, filtrar, buscar paginados (suena fácil — pruébalo según tipos de fecha y localidades)
  • Edición de filas en línea con semántica adecuada de guardado/cancelación y una experiencia de usuario optimista
  • Un formulario de diálogo para creates con búsquedas relacionales ricas
  • Validación que se ejecuta antes de dejar que el usuario guarde
  • Detalle maestro para que el usuario pueda ver el contexto sin necesidad de hacer clic
  • delete confirmation that doesn’t feel hostile
  • Estados de carga / vacío / error que se comunican claramente
  • Accesibilidad del teclado, gestión de enfoque, etiquetas de lectores de pantalla

La mayoría de los equipos shippan el 60% de eso, declaran la victoria y se lo dan a los operadores con un encogimiento de hombros. Ese es el trabajo que la Red de Datos Ignite UI React está destinada a desaparecer.

Configurando el backend CRUD con .NET Core, SQLite.

El backend es puro estándar. Cinco entidades, un EF Core DbContext, cinco pequeños controladores CRUD, Swashbuckle para OpenAPI:

// server/Program.cs
builder.Services.AddDbContext<AppDbContext>(opts =>
    opts.UseSqlite("Data Source=northwind.db"));
builder.Services.AddControllers();
builder.Services.AddSwaggerGen();

Los mandos son exactamente lo que uno imaginaría:

// server/Controllers/ProductsController.cs
[ApiController, Route("api/[controller]")]
public class ProductsController(AppDbContext db) : ControllerBase
{
    [HttpGet]            public Task<List<Product>> GetAll()         => db.Products.AsNoTracking().ToListAsync();
    [HttpPost]           public async Task<Product> Create(Product p) { db.Add(p); await db.SaveChangesAsync(); return p; }
    [HttpPut("{id:int}")]public async Task Update(int id, Product p) { db.Update(p); await db.SaveChangesAsync(); }
    [HttpDelete("{id:int}")] public async Task Delete(int id)        { db.Remove(await db.Products.FindAsync(id)); await db.SaveChangesAsync(); }
}

dotnet runy obtienes una interfaz de Swagger en/swagger. Ahora puedes ver —y llamar— a todos los endpoints sin escribir aún un frontend. Este es el contrato que facilita el React lado: una API REST tipada que el frontend puede reflejar línea por línea.

La capa de servicio frontend refleja la API

// client/src/api/types.ts
export interface Product {
  productID: number;
  productName: string;
  unitPrice: number;
  stockLevel: number;
}

// client/src/api/services.ts
export const ProductsService = {
  list:   ()             => api.get<Product[]>('/api/Products'),
  get:    (id: number)   => api.get<Product>(`/api/Products/${id}`),
  create: (p: Omit<Product, 'productID'>) => api.post<Product>('/api/Products', p),
  update: (p: Product)   => api.put<void>(`/api/Products/${p.productID}`, p),
  remove: (id: number)   => api.del(`/api/Products/${id}`),
};

Los tipos TypeScript coinciden con la forma JSON ASP.NET se serializa por defecto, así que no hay capa de mapeo que mantener.

La parte de la que trata toda esta entrada: la React Red de Datos

Aquí está toda la página de cableado CRUD para la página de Productos.

import {
  IgrGrid, IgrColumn, IgrPaginator,
  IgrActionStrip, IgrGridEditingActions,
} from 'igniteui-react-grids';

<IgrGrid
  data={filtered}
  primaryKey="productID"
  rowEditable={true}
  allowFiltering={true}
  filterMode="excelStyleFilter"
  moving={true}

  onRowEditDone={async (e: CustomEvent) => {
    const row = (e.detail as { newValue?: Product })?.newValue;
    if (!row) return;
    try {
      await ProductsService.update(row);
      toast.success(`Product "${row.productName}" saved.`);
      products.refetch();
    } catch (err) {
      toast.error(`Save failed: ${(err as Error).message}`);
    }
  }}

  onRowDeleted={async (e: CustomEvent) => {
    const row = (e.detail as { data?: Product })?.data;
    if (!row) return;
    try {
      await ProductsService.remove(row.productID);
      toast.success(`Deleted "${row.productName}".`);
      products.refetch();
    } catch (err) {
      toast.error(`Delete failed: ${(err as Error).message}`);
    }
  }}
>
  <IgrColumn field="productID"   header="ID"      editable={false} />
  <IgrColumn field="productName" header="Product" editable={true}  hasSummary />
  <IgrColumn field="unitPrice"   header="Price"
             dataType="number" editable={true}
             bodyTemplate={(c) => <span>{currency(c.cell.value)}</span>} />
  <IgrColumn field="stockLevel"  header="Stock"
             dataType="number" editable={true} hasSummary />

  <IgrPaginator perPage={10} />

  <IgrActionStrip>
    <IgrGridEditingActions addRow={false} />
  </IgrActionStrip>
</IgrGrid>

Eso te da, en un componente:

  • Sortable columns (click the header)
  • Filtros de columna al estilo Excel (el menú en cada cabecera)
  • Paginación (15/30/45 por página) con paginador de pie
  • Arrastre para reordenar columnas
  • Resúmenes numéricos y de cadenas (promedio, suma, recuento) en el pie de página
  • Row pasa el cursor → tira de acción con iconos de Editar / Eliminar
  • Haz clic en Editar → las celdas se vuelven editables, aparecen chips de guardar/cancelar en la parte inferior de la fila
  • onRowEditDonese activa con la nueva fila fusionada → PONERLA en la API
  • onRowDeletedse activa cuando el usuario confirma eliminar → ELIMINARLO de la API

La pieza que quiero destacar esrowEditable={true} más laIgrActionStrip + IgrGridEditingActions combinación. No haces seguimiento ni edición del estado tú mismo. SinisEditing bandera, sin mapa de "celdas sucias", sin el manejador de "¿el usuario pulsó Escape?". La Red de Datos de React la gestiona; Solo escuchas el commit y lo envías a tu servicio.

La otra parte es el renderizado como quieras bodyTemplate. Estoy formateandounitPrice como moneda en el ejemplo anterior. El mismo gancho te permite renderizar las pastillas de estado, avatares, insignias, niveles de stock codificados por colores — cualquier cosa React puedas renderizar — sin renunciar a ordenar ni filtrar el valor subyacente.

Las búsquedas relacionales pertenecen a un Combo, no a una entrada numérica

La edición en línea es genial para primitivas, pero si tu fila tiene claves externas (salesPersonID,productID,shipperID), no quieres que los usuarios escriban IDs. Quieres un desplegable agrupado y buscable.

Enter IgrCombo:

<IgrCombo
  data={salespeople.map((s) => ({
    id: s.salesPersonID,
    name: fullName(s.salesPersonFirstName, s.salesPersonLastName),
    subtitle: s.salesPersonTitle ?? '',
  }))}
  valueKey="id"
  displayKey="name"
  groupKey="subtitle"     // ← grouped headers come for free
  singleSelect
  value={form.salesPersonID != null ? [form.salesPersonID] : []}
  onChange={(e) => {
    const arr = (e.detail as { newValue?: unknown[] }).newValue ?? [];
    setForm((f) => ({ ...f, salesPersonID: (arr[0] as number) ?? null }));
  }}
/>

Funciones empresariales en Ignite UI que a tus usuarios les encantarán: filtrado por escribir, selección múltiple con renderizado por chip, virtualización para miles de elementos y una ranura para plantillas personalizadas.

Si lo combinasIgrCombo conIgrDatePicker yIgrInput tienes toda la historia de "los ricos crean forma" gestionada por Ignite UI React componentes.

Tematización — una importación, hecho

Cuando empecé a crear esta app, tenía un único tema: el tema Material Light incorporado, aplicado con una importación CSS por archivo:

// main.tsx
import 'igniteui-webcomponents/themes/light/material.css';
import 'igniteui-react-grids/grids/themes/light/material.css';

Cada Ignite UI superficie — chevrones, la tira de acción, el lápiz de edición, los botones del paginador, los encabezados de diálogo — recoge el tema automáticamente. A medida que la app evolucionaba, añadí un selector para cambiar temas basados en los cuatro sistemas de diseño que salían de la caja (Material, Fluent, Indigo, Bootstrap) y variantes oscuras para cada uno. Cambia una importación CSS y toda la app cambia de temas.

I also used the Ignite UI MCP servers

Lo construí usando los servidores MCP de Ignite UI para componentes y tematización. En lugar de cablear cada página desde cero, utilicé la indicación para generar y refinar la estructura de la app (front-end y back-end), el uso de componentes y la configuración visual en unos 20 minutos en total.

Si quieres ver exactamente cómo se hizo, el prompt está en el repositorio de GitHub aquí: docs/PROMPTS.md. La configuración MCP que usé es la de Ignite UI CLI MCP más el flujo de trabajo MCP de tematización.

Lo que no tuve que construir

Para concretar la comparación, esto es lo que no tuve que escribir:

  • Un renderizador de tablas virtualizadas
  • Gestión del estado de edición de filas
  • Interfaz, interfaz de filtro de columnas estilo Excel
  • Una caja de combo agrupada con selección múltiple con tip-ahead
  • A date picker that renders a calendar
  • Sincronización de desplazamiento entre navegadores
  • Keyboard navigation across cells
  • Gestión de enfoque para el diálogo de edición
  • Un renderizador de píldora de estado con colores semánticos adecuados
  • Toast / snackbar plumbing
  • Un estilo visual coherente en todo lo anterior

Ese es el valor que se supone. La Ignite UI React Data Grid tiene la forma exacta del trabajo que no quieres hacer dos veces.

Try it

La fuente completa está en github.com/react-grids/react-data-grids-crud. Clona, ejecuta la API .NET, ejecuta el servidor de desarrollo de Vite, y tendrás una consola CRUD funcional en dos terminales.

React Panel CRUD de Data Grid con pedidos de Northwind, detalles de los vendedores y Ignite UI for React

Si quieres usar la React Data Grid en tu propia app, empieza por la página de Ignite UI React Data Grid y haz una prueba gratuita desde ahí.

Mira el vídeo en YouTube:

La cuadrícula que he usado aquí es el paquete comercialigniteui-react-grids. También hay una opción gratuitaIgrGridLite en la licenciaigniteui-react/grid-lite MIT si no necesitas edición de filas, detalle maestro o la tira de acción.

Preguntas más frecuentes

¿Cuál es la forma más rápida de construir una aplicación de administración CRUD en React?

El camino más rápido es empezar con una React Red de Datos y componentes de formulario que ya gestionan las partes difíciles: edición, filtrado, paginación, consultas, validación y accesibilidad. En este proyecto, la Red de Datos Ignite UI React junto con una pequeña capa de servicio tipada eliminó la mayor parte de la fontanería personalizada que normalmente ralentiza el trabajo CRUD.

¿Qué es una React Red de Datos y cuándo la necesitas?

Una React Data Grid es un componente de tabla de alta función diseñado para pantallas interactivas y con muchos datos. Necesitas uno cuando tu aplicación va más allá de las filas de solo lectura y empieza a requerir edición en línea, filtrado avanzado, resúmenes, navegación por teclado, virtualización o flujos de trabajo de datos relacionales.

¿Se puede construir una aplicación CRUD de verdad React con edición en línea en minutos?

Sí, en realidad, puedes hacerlo en minutos. Esta demo incluye pedidos, clientes, productos, remitentes y comerciales con edición de filas en línea, creación de diálogos, confirmación de borrado, detalle maestro y desplegables relacionales en menos de 30 minutos usando la CLI de Ignite UI y Claude Code o GitHub Copilot.

¿Por qué usar Ignite UI for React para aplicaciones CRUD en lugar de construir el comportamiento de la cuadrícula a mano?

Porque la parte cara de las apps CRUD no es renderizar filas. Es el modelo de interacción alrededor de esas filas: ciclo de vida de edición, filtrado de la experiencia de usuario, comportamiento del teclado, búsquedas agrupadas, resúmenes, tematización y transiciones de estado consistentes. Ignite UI presenta esos comportamientos como características del producto, así que el código se mantiene centrado en datos empresariales y llamadas API.

¿Funciona Ignite UI for React con un backend de la API web de .NET?

Sí. En este ejemplo, la interfaz se comunica con una API SQLite de .NET 10 + EF Core sobre endpoints REST estándar. El código cliente se escribe simplemente a través de funciones de servicio TypeScript que llaman/api/Products/api/Orders y las otras rutas CRUD.

¿Lo construiste también con los servidores Ignite UI MCP?

Sí. La app utiliza Ignite UI componentes en tiempo de ejecución, y el flujo de trabajo de compilación también se benefició del Ignite UI CLI MCP y la configuración de la MCP con tematización. Esa combinación ayuda a las herramientas de IA a apoyar páginas, responder preguntas sobre componentes y mantener las decisiones de temática alineadas con Ignite UI patrones.

Is Ignite UI React Data Grid free?

El paquete completoigniteui-react-grids utilizado en esta publicación es comercial. Si solo necesitas una cuadrícula más ligera, Infragistics también ofrece el gratuitoIgrGridLite en el paquete licenciadoigniteui-react/grid-lite por el MIT, aunque funciones avanzadas de CRUD como la edición de filas y las tiras de acción forman parte de la oferta comercial.

¿Qué características son las que más importan en una red de datos CRUD de producción?

La base es ordenar, filtrar, paginar y editar. En la práctica, los equipos también necesitan consultas relacionales, validación, confirmación de borrado, accesibilidad al teclado, contexto maestro-detallado, estados de carga y vacíos, y una tematización que no se deshaga cuando añades más páginas. Esas son las características que suelen decidir si una herramienta interna se siente fiable o frágil.


Tags: #react #react-data-grid #typescript #crud #datagrid #ignite-ui #dotnet #admin-ui #mcp

Solicitar una demostración