Creación de un panel de control experimental con React
Hasta ahora, hemos estructurado el contenido con HTML, añadido interactividad con JavaScript, creado un servidor con Node.js y Express, y completado la API para almacenar y recuperar datos experimentales en una base de datos. Sin embargo, a medida que la interfaz se vuelve más compleja, surgen problemas. Gestionar toda esta información —tarjetas de información genética, listas de muestras, tablas de resultados de control de calidad y botones de filtro— dentro de un único archivo HTML innerHTML hace que el código crezca rápidamente hasta alcanzar miles de líneas.
React resuelve este problema. Es la tecnología para crear tus propios componentes HTML. En lugar de utilizar etiquetas básicas como <div> o <span>, puedes definir y usar directamente componentes con significado propio, como <GeneCard>, <SampleList> o <QcDashboard>. Al igual que en un laboratorio se descomponen procesos complejos en protocolos manejables, React divide la interfaz de usuario en componentes para su gestión.
Componentes: Creación de tus propios componentes
El componente es el núcleo de React. Una única función equivale a un componente:
function GeneCard() {
return (
<div>
<h3>TP53</h3>
<p>Chromosome: 17p13.1</p>
<p>Function: tumor suppressor</p>
</div>
);
}Al crear esta función, se puede utilizar con la etiqueta <GeneCard />. Siempre debe comenzar con una letra mayúscula, ya que React distingue entre las etiquetas HTML estándar (que comienzan con minúscula) y los componentes personalizados (que comienzan con mayúscula).
Se combinan varios componentes para crear la pantalla completa:
function App() {
return (
<div>
<Header />
<GeneCard />
<SampleList />
</div>
);
}App Con solo observar una función, se puede comprender en un instante que esta pantalla está compuesta por Header, GeneCard y SampleList. El HTML complejo queda oculto tras nombres descriptivos.
Tres ventajas de los componentes:
- Legibilidad: La estructura del código es fácilmente visible.
- Reutilización: Si necesitas
<GeneCard />en 10 lugares, simplemente úsalo 10 veces. - Mantenimiento: Si deseas cambiar el diseño de la tarjeta, solo debes modificar la función
GeneCarduna vez, y todas las tarjetas se actualizarán simultáneamente.
Props: Pasar datos a los componentes
El GeneCard anterior siempre muestra únicamente TP53. Para mostrar también otros genes, se utilizan Props (abreviatura de Properties). Es un concepto similar a los parámetros de una función:
function GeneCard(props) {
return (
<div>
<h3>{props.name}</h3>
<p>Chromosome: {props.chromosome}</p>
<p>Function: {props.geneFunction}</p>
</div>
);
}
function App() {
return (
<div>
<GeneCard name="TP53" chromosome="17p13.1" geneFunction="tumor suppressor" />
<GeneCard name="BRCA1" chromosome="17q21.31" geneFunction="DNA repair" />
<GeneCard name="EGFR" chromosome="7p11.2" geneFunction="receptor tyrosine kinase" />
</div>
);
}<GeneCard name="TP53" chromosome="17p13.1" /> tiene name, chromosome y geneFunction como props. React agrupa estos valores en un solo objeto y los pasa como el primer parámetro (props) de la función.
En JSX, las llaves {} indican "esta es la zona de JavaScript". Si escribes {props.name}, se imprimirá el valor de name dentro del objeto props. Si escribes props.name sin llaves, aparecerá literalmente en la pantalla.
Si lo comparamos con un protocolo experimental: GeneCard es el marco del protocolo y las props son las muestras que se colocan en ese marco. Es el mismo protocolo, pero el resultado varía según la muestra (los datos).
Renderizado de listas: convertir datos de arreglos en componentes
Si en lugar de 3 muestras hubiera 100, no podrías escribir <GeneCard /> 100 veces. Los datos de los arreglos se procesan mediante un bucle:
function SampleList(props) {
const items = [];
for (let i = 0; i < props.samples.length; i++) {
const sample = props.samples[i];
items.push(
<li key={sample.id}>
{sample.id}: OD={sample.od} — {sample.status}
</li>
);
}
return (
<ul>{items}</ul>
);
}
function App() {
const sampleData = [
{ id: "S001", od: 1.85, status: "pass" },
{ id: "S002", od: 0.42, status: "fail" },
{ id: "S003", od: 2.10, status: "pass" }
];
return (
<div>
<h2>Resultados del QC de muestras</h2>
<SampleList samples={sampleData} />
</div>
);
}Algunos puntos a tener en cuenta:
key={sample.id}— Los elementos creados mediante iteración deben tener unkeyúnico. React lo utiliza para rastrear qué elemento ha cambiado. Es similar a asignar un número de identificación único a cada muestra en el laboratorio.samples={sampleData}— Al pasar un array como prop, debe estar entre llaves. Las cadenas de texto van entre comillas, mientras que los valores de JavaScript (arrays, números, variables) van entre llaves.
Estado: gestión de datos cambiantes
Las props son valores recibidos desde el exterior y no se pueden modificar dentro del componente. Es como no poder cambiar arbitrariamente los valores especificados en una ficha de condiciones experimentales durante el proceso. Sin embargo, el estado del experimento cambia continuamente: "en espera" → "en progreso" → "completado". Gestionar este estado interno es lo que se conoce como Estado.
function ExperimentTracker() {
const [status, setStatus] = React.useState("En espera");
const [count, setCount] = React.useState(0);
function handleStart() {
setStatus("En curso");
setCount(count + 1);
}
function handleComplete() {
setStatus("Completado");
}
return (
<div>
<p>Estado del experimento: {status}</p>
<p>Número de ejecuciones: {count}</p>
<button onClick={handleStart}>Iniciar experimento</button>
<button onClick={handleComplete}>Completar experimento</button>
</div>
);
}React.useState("en espera") devuelve dos elementos:
status: el valor actual ("pendiente")setStatus: la función para modificar el valor
Cuando se llama a setStatus("en curso"), status cambia y React vuelve a renderizar automáticamente la pantalla. No es necesario manipular el DOM directamente con innerHTML. Basta con modificar el estado para que la pantalla se actualice automáticamente. Esta es una de las principales ventajas de React.
| Props | Estado | |
|---|---|---|
| Origen | Proviene del exterior | Gestionado internamente |
| Modificabilidad | No (solo lectura) | Sí (con setState) |
| Analogía | Condiciones experimentales especificadas en el protocolo | Estado de progreso del experimento |
| Ejemplo | Nombre del gen, posición del cromosoma | "pendiente" → "en progreso" → "completado" |
Ejemplo completo: panel de control de control de calidad
Al combinar los componentes, las props y el estado que hemos visto hasta ahora, podemos crear un panel de control de control de calidad sencillo:
function QcResult(props) {
const style = {
color: props.passed ? "green" : "red",
fontWeight: "bold"
};
return (
<tr>
<td>{props.sampleId}</td>
<td>{props.od}</td>
<td style={style}>{props.passed ? "PASS" : "FAIL"}</td>
</tr>
);
}
function QcDashboard() {
const samples = [
{ id: "S001", od: 1.85, passed: true },
{ id: "S002", od: 0.42, passed: false },
{ id: "S003", od: 2.10, passed: true },
{ id: "S004", od: 0.15, passed: false }
];
const passCount = samples.filter(function(s) { return s.passed; }).length;
return (
<div>
<h2>QC Dashboard</h2>
<p>Aprobadas: {passCount} / {samples.length}</p>
<table>
<thead>
<tr><th>ID de muestra</th><th>OD</th><th>Resultado</th></tr>
</thead>
<tbody>
{samples.map(function(s) {
return <QcResult key={s.id} sampleId={s.id} od={s.od} passed={s.passed} />;
})}
</tbody>
</table>
</div>
);
}QcResult es un componente que muestra los resultados de una sola muestra, mientras que QcDashboard es el componente que engloba todos los demás. Incluso si los datos aumentan a 100 registros, el componente QcResult no necesita cambiar ni una sola línea; solo hay que añadir los datos.
Pruébalo tú mismo (Ejemplo simplificado)
Completa los espacios en blanco del siguiente ejemplo para crear un componente de React que muestre información genética.
function GeneInfo() {return (<div><h3>{props.}</h3><p>Length: {.length_bp} bp</p></div>);}// Uso: <GeneInfo name="TP53" length_bp={19149} />
Errores comunes y soluciones
P: El componente no se muestra en la pantalla
Si el nombre del componente comienza con una letra minúscula, React lo interpreta como una etiqueta HTML estándar. Cambie la primera letra a mayúscula: geneCard → GeneCard.
P: Advertencia de Each child in a list should have a unique "key" prop
Los elementos creados con un bucle no tienen la prop key. Asigne un valor único (como un ID o un número de muestra) que esté presente en cada elemento del array a key. No se recomienda usar el índice (i) como clave.
P: ¿Cuándo debo usar llaves y comillas?
Use comillas para cadenas de texto: name="TP53". Use llaves para valores de JavaScript, como números, arrays o variables: count={42}, data={myArray}. Para ejecutar código JavaScript dentro de JSX, encierre el código entre llaves: {props.name}.
P: Modifiqué el estado directamente, pero la pantalla no se actualizó
Si modifica el valor directamente, como en status = "completado", React no detectará el cambio. Siempre debe usar la función setter, por ejemplo, setStatus("completado"), para que React vuelva a renderizar la pantalla.