Menu

Preguntas de entrevista de React con respuestas (React 19)

Unas 30 preguntas de entrevista de React, de nivel principiante a avanzado, cada una con una respuesta corta que un entrevistador aceptaría y código en vivo para las que se entienden mejor viéndolas que leyéndolas.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Estas son las preguntas de entrevista de React que aparecen con más frecuencia, agrupadas por nivel y respondidas como espera un entrevistador: de forma breve, correcta para React 19 y con la razón detrás de la regla. Donde ver el comportamiento es mejor que leer sobre él, la respuesta tiene un editor en vivo, y algunas preguntas te piden predecir la salida de la consola antes de ejecutarlo.

Antes de hacer clic: ¿qué imprime la consola bajo la vista previa, y qué muestra el botón? La respuesta está en la sección para principiantes de abajo.

Preguntas para principiantes

¿Qué es React?

React es una librería de JavaScript para construir interfaces de usuario a partir de componentes. Escribes funciones que devuelven una descripción de la UI para los datos actuales, y cuando esos datos cambian React calcula qué cambió y actualiza el DOM por ti. Solo se encarga de la capa de vista: el enrutamiento, la obtención de datos y los formularios vienen de otras librerías o de un framework como Next.js.

¿Qué es JSX?

JSX es una extensión de sintaxis que te permite escribir marcado dentro de JavaScript. Un compilador (Babel, esbuild, SWC) convierte cada etiqueta en una llamada que crea un elemento de React, así que <p className="note">{text}</p> se convierte en un objeto con type: 'p' y las props. Como es JavaScript, usas className en lugar de class, pones las expresiones entre {}, y todas las etiquetas deben cerrarse. La página de JSX cubre las reglas en detalle.

¿Cuál es la diferencia entre un componente y un elemento?

Un componente es una función (o clase) que recibe props y devuelve UI. Un elemento es el objeto simple que produce JSX, que describe qué renderizar: <Avatar size={40} /> es un elemento cuyo type es la función Avatar. React llama a tu componente para convertir elementos en más elementos, hasta llegar a las etiquetas del DOM. Los elementos son baratos e inmutables; nunca llamas tú mismo a un componente.

¿Cuál es la diferencia entre props y estado?

Las props las pasa el padre y son de solo lectura dentro del componente. El estado pertenece al componente, cambia con el tiempo mediante un setter, y cada cambio programa un nuevo renderizado. Una forma habitual de decirlo: las props configuran un componente, el estado es su memoria. El mismo valor puede ser estado en un padre y prop en su hijo.

¿Qué registra el primer ejemplo de esta página?

Registra logged: 0, y el botón muestra Count: 1, no 2. El estado es una instantánea: count es una constante durante todo el renderizado, así que ambas llamadas a setCount(count + 1) calculan 0 + 1, y el registro lee el valor viejo porque el nuevo solo existe en el siguiente renderizado. Para sumar dos, usa la forma de actualización: setCount((c) => c + 1) dos veces.

¿Por qué las listas necesitan keys, y por qué el índice es una mala key?

React usa la key para emparejar cada elemento de la lista con el del renderizado anterior. Si usas el índice del array e insertas un elemento arriba, todos los índices se desplazan, así que React conserva el estado de cada fila en su posición vieja y lo une a los datos equivocados.

Marca a Ada y luego haz clic en "Add to top": la marca salta a la nueva primera fila. Cambia key={index} por key={person.id} y vuelve a probar, y la marca se queda con Ada. En desarrollo React también avisa cuando faltan keys; la vista previa funciona como un build de producción, así que aquí no verás ese aviso.

¿Qué es un input controlado?

Un input cuyo valor viene del estado de React: pasas value y actualizas el estado en onChange, así que React es la única fuente de verdad y puedes validar o transformar cada pulsación. Un input no controlado guarda su propio valor en el DOM y lo lees cuando lo necesitas, mediante una ref o el FormData del formulario. Los inputs controlados son la opción por defecto cuando la UI reacciona a lo que escribe el usuario.

¿Qué significa elevar el estado?

Cuando dos componentes necesitan los mismos datos, mueves el estado a su padre común más cercano y lo pasas hacia abajo como props, junto con una función para cambiarlo. Los hijos dejan de tener sus propias copias, así que nunca pueden contradecirse. Es la respuesta estándar a "cómo comparten estado los componentes hermanos" antes de recurrir al contexto o a un store.

¿Cuáles son las reglas de los hooks?

Llama a los hooks solo en el nivel superior de un componente o de un hook personalizado, nunca dentro de condiciones, bucles o funciones anidadas, y solo desde funciones de React, no desde funciones de JavaScript normales. React identifica cada hook por el orden de las llamadas, así que ese orden debe ser idéntico en cada renderizado. El paquete eslint-plugin-react-hooks hace cumplir ambas reglas.

¿Qué es un fragmento?

Un fragmento agrupa varios elementos sin agregar un nodo al DOM: <>...</>, o <Fragment key={id}> cuando necesitas una key dentro de una lista. Un componente debe devolver una sola raíz, y los fragmentos permiten que esa raíz sean varios hermanos, lo que importa dentro de tablas y layouts flex, donde un div extra rompería el marcado.

Preguntas de nivel intermedio

¿Cómo funciona el array de dependencias de useEffect?

React ejecuta el efecto después de que el renderizado se confirma (normalmente después de que el navegador pinta), y otra vez después de cualquier renderizado posterior en el que haya cambiado un valor del array (comparado con Object.is). Sin array se ejecuta después de cada renderizado; con [] se ejecuta una vez después del primer renderizado. Cada valor del componente que lee el efecto va en el array, y el linter te avisa cuando falta uno.

¿Cuándo se ejecuta la limpieza de un efecto?

La función que devuelves desde un efecto se ejecuta antes de que el efecto vuelva a ejecutarse con nuevas dependencias, y una vez cuando el componente se desmonta. Ahí deshaces lo que configuró el efecto: limpiar un temporizador, quitar un listener, cerrar una conexión.

Haz clic en "Switch room" y mira la consola: primero se ejecuta la limpieza de la sala vieja, y luego el efecto se conecta a la nueva. "Hide chat" solo ejecuta la limpieza. En desarrollo, StrictMode agrega al montar una conexión, desconexión y conexión extra para comprobar que tu limpieza funciona; la vista previa funciona como un build de producción, así que solo ves la secuencia real.

¿Por qué mi estado parece viejo dentro de setInterval?

El callback del intervalo es una closure sobre el count del renderizado que lo creó. Con un array de dependencias vacío el efecto nunca se vuelve a ejecutar, así que el callback sigue leyendo ese primer count para siempre.

broken llega a 1 y se detiene, porque cada tic calcula 0 + 1. fixed sigue contando, porque la función de actualización recibe el valor más reciente. Agregar broken al array de dependencias también funciona, a costa de limpiar y volver a crear el intervalo cada segundo.

¿Qué es el batching?

React agrupa varias actualizaciones de estado en un solo renderizado. Desde React 18 esto se aplica en todas partes: manejadores de eventos, timeouts, promesas y listeners de eventos nativos. Si necesitas que el DOM se actualice justo después de una actualización, flushSync de react-dom te permite salirte, pero rara vez lo necesitas.

El clic registra un solo render 1 1 1, no tres renderizados. Tres actualizaciones de estado dentro de un timeout significaban tres renderizados antes de React 18.

¿Qué registra esto? (orden de los efectos)

Lee el código y anota las cuatro líneas que imprimirá la consola, en orden, antes de mirarla.

El renderizado va de arriba abajo: render App y luego render Child. Los efectos se ejecutan de abajo arriba, después de que todo el árbol se confirmó: effect Child y luego effect App. El efecto de un padre puede contar con que los efectos de sus hijos ya se ejecutaron.

¿Cuál es la diferencia entre useMemo y useCallback?

useMemo(() => compute(a, b), [a, b]) guarda en caché el resultado de un cálculo. useCallback(fn, [deps]) guarda en caché la función en sí, así que equivale a useMemo(() => fn, [deps]). Ambos solo ayudan cuando algo más abajo compara por referencia: un hijo con memo, o el array de dependencias de otro hook. Desde React Compiler 1.0 (octubre de 2025) un paso del build puede agregar esta memoización automáticamente, pero la memoización manual sigue funcionando y la seguirás viendo en la mayor parte del código.

¿Qué hace React.memo, y por qué suele necesitar useCallback?

memo(Component) se salta volver a renderizar el componente cuando sus props son las mismas que la última vez, comparadas una por una con Object.is. Una función escrita en línea en el padre es una función nueva en cada renderizado, así que cuenta como una prop cambiada y anula memo. useCallback mantiene la misma función entre renderizados.

Limpia la consola y haz clic en "Re-render parent": solo aparece render inline handler. El otro hijo recibió la misma función y se lo saltó. Quita memo(...) alrededor de Button y ambos registran en cada clic, lo que muestra que useCallback por sí solo no hace nada.

¿Qué es el contexto, y qué cuesta?

El contexto pasa un valor a todos los componentes por debajo de un proveedor sin hacerlo pasar por props: createContext, luego <ThemeContext value={theme}> en React 19 (o <ThemeContext.Provider>), y useContext(ThemeContext) para leerlo. El costo es que cada componente que lee el contexto se vuelve a renderizar cuando el valor cambia, y memo no lo impide. Mantenlo barato separando los valores no relacionados en contextos distintos, envolviendo un valor de objeto en useMemo y dejando el estado que cambia rápido fuera del contexto global de la app. Consulta useContext.

¿Qué son las refs, y cuándo usas una en lugar de estado?

useRef(initial) devuelve un objeto cuya propiedad current persiste entre renderizados, y cambiarla no provoca un renderizado. Usa una ref para valores de los que no depende la pantalla (el id de un temporizador, el valor anterior, una bandera) y para acceder al DOM (<input ref={inputRef}> y luego inputRef.current.focus()). Si el valor se muestra en pantalla, va en el estado.

¿Qué es el DOM virtual, y qué es la reconciliación?

En cada renderizado React construye un nuevo árbol de elementos y lo compara con el anterior; esta comparación es la reconciliación. Si el tipo de un elemento cambió (un div pasó a ser una section, o ProfileA pasó a ser ProfileB), React destruye ese subárbol con su estado y construye uno nuevo. Si el tipo es el mismo, conserva el nodo del DOM y actualiza las props que cambiaron, y usa las keys para emparejar los hijos en las listas. "DOM virtual" es el nombre popular de ese árbol en memoria; la velocidad viene de tocar solo lo que cambió, no de que el árbol en sí sea rápido.

¿Qué es un hook personalizado?

Una función cuyo nombre empieza con use y que llama a otros hooks, para que puedas reutilizar lógica con estado entre componentes: useOnlineStatus, useLocalStorage, useDebouncedValue. Cada componente que lo llama recibe su propio estado independiente; un hook personalizado comparte lógica, no datos. Consulta hooks personalizados.

¿Qué hace StrictMode?

<StrictMode> activa comprobaciones extra solo en desarrollo. Renderiza los componentes dos veces para exponer los renderizados impuros, ejecuta al montar los efectos como configuración, limpieza y configuración para exponer las limpiezas que faltan, hace lo mismo con las ref callbacks y avisa sobre APIs obsoletas. Nada de esto ocurre en un build de producción, así que un registro doble en la consola durante el desarrollo es esperable y no es un error.

Preguntas avanzadas

¿Qué registra esto? (render, layout effect, effect)

Una predicción más. Tres registros, tres momentos distintos de un renderizado.

El orden es render, luego useLayoutEffect y luego useEffect, aunque useEffect está escrito primero. Los layout effects se ejecutan después de que React actualiza el DOM pero antes de que el navegador pinte, y por eso sirven para medir un elemento; los efectos normales se ejecutan después, normalmente tras el pintado, y deberían ser la opción por defecto.

¿Qué es un error boundary?

Un componente de clase que captura los errores lanzados al renderizar sus hijos y muestra un fallback en lugar de desmontar toda la app. Necesita static getDerivedStateFromError (para pasar al fallback) y normalmente componentDidCatch (para registrar). Todavía no hay un equivalente en hooks, así que en código con componentes de función los equipos escriben una clase o usan el paquete react-error-boundary.

Haz clic en "Break it": el fallback reemplaza solo a los hijos del boundary, el botón se queda, y React sigue reportando el error capturado en la consola. Los boundaries no capturan errores en manejadores de eventos, en código async como setTimeout, ni en el propio boundary. Para esos usas try/catch y cambias el estado.

¿Qué es un portal?

createPortal(children, domNode) de react-dom renderiza hijos en otro nodo del DOM, normalmente document.body, mientras los mantiene en el mismo lugar del árbol de React. Los modales, tooltips y avisos lo usan para escapar del overflow: hidden o del contexto de apilamiento de un padre. El contexto sigue funcionando a través de un portal, y los eventos se propagan por el árbol de React, así que un clic dentro del portal llega al onClick del padre aunque los nodos del DOM estén en otro lugar. Consulta portales.

¿Qué son Suspense y lazy?

lazy(() => import('./Chart')) carga el código de un componente la primera vez que se renderiza, lo que divide tu bundle. <Suspense fallback={<Spinner />}> muestra el fallback mientras algo dentro todavía está cargando: código lazy, o datos leídos con use(promise) o con un framework que admita Suspense. Dónde colocas los límites decide qué partes de la página esperan juntas.

import { lazy, Suspense } from 'react';

const Chart = lazy(() => import('./Chart.jsx'));

export default function Dashboard() {
    return (
        <Suspense fallback={<p>Loading chart...</p>}>
            <Chart />
        </Suspense>
    );
}

¿Qué hace useTransition?

Marca una actualización de estado como no urgente. const [isPending, startTransition] = useTransition() y startTransition(() => setTab('posts')) permiten que React mantenga la pantalla actual con buena respuesta e interrumpa el renderizado lento si llega una actualización más urgente, como una pulsación de tecla. isPending te indica que muestres una pista. En React 19 la función que pasas puede ser async, que es lo que React llama una acción. No lo uses para actualizar el propio valor de un input de texto; esa actualización debe ser urgente.

¿Qué son los React Server Components?

Componentes que se ejecutan solo en el servidor (o al hacer el build) y envían al navegador su resultado renderizado, nunca su código. Pueden ser async y leer directamente una base de datos o el sistema de archivos, pero no pueden usar estado, efectos ni APIs del navegador. Un archivo marcado con 'use client' inicia un límite de cliente donde viven los componentes interactivos, y 'use server' marca funciones de servidor que el código de cliente puede llamar. Los usas mediante un framework como Next.js con el App Router; las apps de Vite normales no tienen un servidor para ejecutarlos.

¿Qué cambió en React 19?

  • Actions: funciones async en transiciones, con el estado pendiente manejado por ti. Un <form action={fn}> llama a fn con el FormData del formulario.
  • Nuevos hooks: useActionState para el resultado y el estado pendiente de un formulario, useOptimistic para UI optimista, y useFormStatus en react-dom.
  • use: lee una promesa (suspendiendo hasta que se resuelve) o un contexto, y a diferencia de otros hooks se puede llamar dentro de una condición.
  • ref como prop: los componentes de función reciben ref como cualquier otra prop, así que forwardRef ya no hace falta en el código nuevo. Las ref callbacks pueden devolver una función de limpieza.
  • <Context> como proveedor, además de las etiquetas <title> y <meta> que suben al head del documento.
  • Eliminaciones: ReactDOM.render, las string refs, el contexto heredado y defaultProps en componentes de función (usa parámetros por defecto).
// React 19: ref is a normal prop
function TextInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;
}

La página de React 19 tiene ejemplos ejecutables de cada uno.

¿Cómo pruebas componentes de React?

Con React Testing Library y un runner como Vitest o Jest. Renderizas el componente, buscas los elementos como lo haría un usuario (por rol, etiqueta o texto), interactúas con user-event y haces aserciones sobre lo que se ve, no sobre el estado interno. Así las pruebas siguen siendo válidas tras una refactorización.

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('counts clicks', async () => {
    const user = userEvent.setup();
    render(<Counter />);
    await user.click(screen.getByRole('button', { name: /clicked 0 times/i }));
    expect(screen.getByRole('button')).toHaveTextContent('Clicked 1 times');
});

toHaveTextContent viene de @testing-library/jest-dom. Para flujos completos entre páginas, los equipos agregan Playwright o Cypress encima.

¿Cómo encuentras y corriges un problema de rendimiento?

Mide primero. Abre la pestaña Profiler de React DevTools, graba la interacción lenta y lee el flame chart: muestra qué componentes renderizaron, cuánto tardó cada uno y (con la opción "record why each component rendered") por qué. Las soluciones típicas, en el orden en que conviene probarlas: bajar el estado para que dependan de él menos componentes, pasar los subárboles lentos como children, memoizar la parte costosa con memo, useMemo y useCallback, virtualizar las listas largas, y diferir las actualizaciones pesadas con useTransition o useDeferredValue. Perfila en un build de producción o de profiling; los builds de desarrollo son más lentos y exageran los tiempos de renderizado.

¿Por qué un componente debe ser puro?

Con las mismas props, el mismo estado y el mismo contexto, un componente debe devolver el mismo JSX y no cambiar nada fuera de sí mismo mientras renderiza. React puede renderizar un componente más de una vez, fuera de orden, o descartar un renderizado (transiciones, Suspense, StrictMode), así que los efectos secundarios en el cuerpo, como mutar una variable o enviar una petición, se ejecutan un número impredecible de veces. Los efectos secundarios van primero en los manejadores de eventos, y en los efectos cuando ningún evento los causó.

¿Cuándo no deberías usar un efecto?

Cuando el valor se puede calcular durante el renderizado (listas filtradas, nombres completos, totales), cuando el trabajo lo provoca una acción del usuario (ponlo en el manejador de eventos), y cuando quieres reiniciar el estado al cambiar una prop (usa una key). Los efectos sirven para sincronizar con algo fuera de React: una conexión de red, una API del navegador, un widget de terceros. Las cadenas de efectos que cambian el estado son una fuente habitual de renderizados extra y de errores.

Preguntas frecuentes

¿Qué es React?

React es una librería de JavaScript para construir interfaces de usuario a partir de componentes. Describes cómo debe verse la pantalla para los datos actuales, y React actualiza el DOM real cuando esos datos cambian.

¿Cuál es la diferencia entre estado y props?

Las props son entradas que un padre pasa a un componente, y el componente las trata como de solo lectura. El estado son datos que pertenecen a un componente y cambian con el tiempo mediante un setter, lo que hace que React lo vuelva a renderizar.

¿Qué son los hooks en React?

Los hooks son funciones cuyo nombre empieza con use que permiten a un componente de función usar características de React: useState para el estado, useEffect para efectos secundarios, useContext para el contexto, useRef para valores que no provocan renderizados, y más.

¿Qué es el DOM virtual?

Es el nombre de la descripción en memoria de la UI que mantiene React. En cada renderizado React construye una descripción nueva, la compara con la anterior y aplica al DOM real solo las diferencias. Esa comparación se llama reconciliación.

¿Por qué importan las keys en las listas de React?

Una key le dice a React qué elemento de una lista es cuál entre renderizados. Con keys estables (como un id) React mantiene el estado y el nodo DOM de cada elemento unidos a los datos correctos cuando se agregan, quitan o reordenan elementos. Usar el índice del array rompe esto cuando cambia el orden.

¿Qué es JSX?

JSX es una extensión de sintaxis que te permite escribir marcado parecido a HTML en JavaScript. Un compilador convierte cada etiqueta en una llamada a función que crea un elemento de React, así que <h1>Hi</h1> se convierte en un objeto simple que describe un h1.

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

COMENZAR