Veinte preguntas de la entrevista de React que distinguen el uso del verdadero entendimiento
DOM virtual, claves, efectos, memorización, Contexto, SSR e hidratación: explicados con las preguntas difíciles que realmente plantean los entrevistadores, no con definiciones de libro de texto.
Desarrollar con React y explicar React son habilidades diferentes. Las entrevistas se centran en esta segunda: qué ocurre al llamar a setState, por qué son importantes las claves y cuándo se vuelven a ejecutar los efectos. Las veinte preguntas siguientes aparecen constantemente. Las respuestas se basan en el problema que resuelve cada funcionalidad y en los problemas que surgen en producción, no en repeticiones de textos de libro de texto.
1. Qué es realmente el Virtual DOM
El DOM virtual no es un polvo mágico de aceleración. Es un árbol simple de JavaScript que describe cómo debería verse la interfaz de usuario. Al cambiar el estado, React crea un nuevo árbol virtual, lo compara con el anterior y lo armoniza aplicando solo las modificaciones necesarias al DOM del navegador. Las operaciones reales en el DOM desencadenan tareas de diseño y dibujo; mutar objetos JavaScript es económico, por lo que React utiliza la CPU en memoria para evitar sobrecargar al navegador. Ese diseño tiene como objetivo minimizar la carga del navegador, no hacer que cada comparación sea gratuita. Decir “el DOM virtual siempre es más rápido” sin esa matización es una trampa común entre los desarrolladores principiantes.
2. DOM virtual versus DOM del navegador
Las actualizaciones reales del DOM son costosas y pueden provocar un nuevo flujo de renderizado y una nueva pintura de la interfaz. Las actualizaciones virtuales consisten en diferencias entre objetos en memoria; React agrupa las operaciones costosas de escritura en el DOM en lotes en lugar de realizarlas una por cada llamada al estado. Editar con track-changes es mejor que volver a escribir todo el documento cada vez que se comete un error de escritura.
3. Por qué son importantes las claves de lista cuando se mueven las filas
Las claves identifican los elementos a lo largo de los renders. Sin ellas, React recurre a la posición del índice, lo cual falla cuando se insertan, eliminan o reorganizan los elementos. Usar el índice del array como clave “funciona” hasta que la reorganización hace que los campos de entrada y las casillas de verificación queden asociados a filas incorrectas: un falso “fuga de estado” que en realidad es un error en las claves. Es preferible utilizar identificadores únicos y estables provenientes de los datos; los índices solo deben usarse para listas verdaderamente estáticas. Si el producto permite reorganizar o filtrar arrastrando y soltando, usar índices como claves acabará dañando el estado local de las filas.
4. Explicar useState desde los principios básicos
Los usuarios comunes mueren cuando una función devuelve un valor. useState proporciona a los componentes funcionales memoria persistente y programa una nueva renderización cuando esa memoria cambia:
const [count, setCount] = useState(0);
count es el valor actual; setCount solicita una actualización. La actualización no se aplica durante la renderización: registrar count inmediatamente después de setCount sigue mostrando el valor anterior, ya que el nuevo valor aparece en la siguiente renderización.
5. Por qué las actualizaciones de useState parecen demoradas o agrupadas
React agrupa las actualizaciones que ocurren en el mismo evento para convertirlas en una sola renderización. Desde React 18, ese agrupamiento también incluye promesas y temporizadores, no solo los manejadores de eventos de React. Cuando necesites el valor más reciente basado en el estado anterior, utiliza el actualizador funcional:
setCount(prev => prev + 1);
Ese formulario muestra el valor más reciente de la cola en lugar de una instantánea obsoleta del cierre. Los entrevistadores suelen preguntar qué ocurre si se cierra sobre count dentro de un tiempo límite sin el formulario de actualización.
6. ¿Qué problema resuelve realmente useEffect?
El renderizado debería ser una función pura que convierta los props y el estado en JSX. Las aplicaciones también obtienen datos, adjuntan oyentes de eventos, programan temporizadores y modifican el DOM: efectos secundarios. useEffect ejecuta ese trabajo impuro después de realizar el commit, no durante el renderizado:
useEffect(() => {
const id = setInterval(() => console.log("tick"), 1000);
return () => clearInterval(id); // cleanup
}, []);
La función de limpieza devuelta se ejecuta antes del siguiente efecto y al desmontar la componente. Si se omite, los entrevistadores preguntarán sobre temporizadores duplicados y oyentes que siguen funcionando después del desmontaje.
7. ¿Qué controla realmente el array de dependencias?
Indica a React cuándo volver a ejecutar el efecto mediante comparaciones superficiales:
[]— una vez después del montaje[count]— nuevamente cuando cambiacount- omitido — después de cada renderizado (rara vez deseado)
Si olvidas un valor referenciado en el array, obtendrás una cierre obsoleto: el efecto mantiene para siempre el primer valor capturado. Existen reglas de linteo de dependencias exhaustivas porque este tipo de error es muy común.
8. Componentes controlados vs. no controlados
Los inputs controlados toman el value del estado de React y se actualizan a través de onChange; React es quien controla la verdad.
Los inputs no controlados mantienen el estado del DOM; se leen mediante ref cuando es necesario (a menudo al enviar el formulario).
// Controlled
<input value={name} onChange={e => setName(e.target.value)} />
// Uncontrolled
<input ref={inputRef} defaultValue="Dev" />
El modo controlado permite la validación y formato en tiempo real, pero a costa de un renderizado por cada tecla pulsada. El modo no controlado mantiene un peso menor cuando solo se necesita el valor final. Son posibles formularios mixtos, con algunos campos controlados y otros no, pero resulta más difícil analizarlos durante las revisiones.
9. Transmisión de propiedades y cuándo detenerse
La transmisión de propiedades retransmite los datos a través de capas que únicamente los envían hacia adelante. Los nombres modificados afectan a muchos archivos. El contexto es útil para temas, autenticación o configuraciones regionales; Redux o Zustand son de ayuda cuando los gráficos de estado se vuelven complejos. Matiz: el contexto no es gratuito, ya que cada consumidor vuelve a renderizarse cuando cambia el valor; por lo tanto, no es la opción predeterminada para todos los campos compartidos. Pasar propiedades a dos niveles suele ser más claro que crear un proveedor de contexto solo para un valor ocasional.
10. ¿Cuándo usar useReducer en lugar de useState?
Utiliza useReducer cuando las actualizaciones se dividen por tipo de acción, el estado siguiente depende del estado anterior de maneras complejas, o varios campos cambian al mismo tiempo:
function reducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "reset": return { count: 0 };
default: return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
Es un mini-Redux dentro del componente. Un interruptor booleano se maneja con useState; la lógica de transición complicada debe ir en un reducer que sea posible probar. Sacar esa lógica de los manejadores de eventos de JSX también simplifica las pruebas unitarias al no ser necesario renderizar todo el árbol.
11. Explica useMemo vs useCallback sin limitarte a citar la documentación
Ambos evitan realizar tareas redundantes entre renders para diferentes tipos de datos:
useMemoalmacena un valor calculadouseCallbackalmacena una referencia a función
const sorted = useMemo(() => expensiveSort(list), [list]);
const handleClick = useCallback(() => doThing(id), [id]);
La identidad de la función es importante porque cada renderizado crea un nuevo objeto de función. Pasar una función nueva a un hijo memo anula esa memorización; useCallback mantiene estable la referencia. No utilice estos hooks en todas partes: la memorización tiene un costo. Úselos para tareas costosas que requieran cálculo detallado o para hijos que ya estén memorizados. La memorización prematura es un error frecuente entre los desarrolladores principiantes al que a los entrevistadores les gusta señalar.
12. React.memo es útil… y fácil de anular
React.memo omite un nuevo renderizado cuando los props son superficialmente iguales. Los nuevos literales de objeto o array se consideran diferentes incluso si su contenido es idéntico, por lo que { style: { color: 'red' } } hace que memo sea inútil a menos que los padres estabilicen los props con useMemo/useCallback. De lo contrario, memo añade un costo adicional por comparación sin evitar que el hijo realice sus operaciones.
13. Las claves como identidad, no solo una advertencia de la consola
Las claves son el sistema de identidad de React entre renders. Las claves incorrectas reutilizan el nodo DOM equivocado para los datos inadecuados: el estado del formulario se mantiene en otra fila, las animaciones se activan en el elemento incorrecto, y useState de los elementos de lista conserva el valor del elemento anterior. Parece una corrupción de estado; en realidad es un error con las claves. Mostrar una lista con index-key defectuosa en un entorno aislado es una de las formas más rápidas de asimilar esta regla.
14. Contexto: usos correctos e incorrectos
El contexto comparte valores que necesitan muchos componentes sin la necesidad de pasarlos como propiedades: usuario autenticado, tema y configuración regional:
const ThemeContext = createContext();
<ThemeContext.Provider value={theme}>
<App />
</ThemeContext.Provider>
No es adecuado para estados de alta frecuencia (valores de formulario por tecla) en un árbol grande, ya que cada consumidor se actualiza con cada cambio sin una suscripción selectiva. Es preferible utilizar un almacén con suscripciones más detalladas para ese tipo de casos. Los interruptores de tema son un ejemplo clásico de adecuación al contexto; las posiciones del cursor en un editor colaborativo, por lo general, no lo son.
15. Asociación de ciclos de vida de las clases a efectos
Asociación aproximada de clases:
componentDidMount→useEffect(..., [])componentDidUpdate→useEffect(..., [dep])componentWillUnmount→ limpieza de efectos
El cambio más profundo: los ciclos de vida piensan en tiempo (montar/actualizar/desmontar); los efectos piensan en sincronización —mantener este sistema externo alineado con estos valores—, y por eso los efectos se vuelven a ejecutar cuando cambian las dependencias. Tratar los efectos como métodos de ciclo de vida traducidos línea por línea es la forma en que la gente termina luchando contra el array de dependencias.
16. Estado en comparación con props
Los props son entradas de solo lectura provenientes de un padre. El estado es el dato propio que provoca una nueva renderización cuando cambia. Los props configuran un componente desde el exterior; el estado es lo que este recuerda sobre sí mismo. El label de un botón es un prop; el hecho de que esté deshabilitado mientras se procesa una solicitud es estado. Confundir los dos conduce a patrones antiétnicos como intentar mutar props o elevar demasiado alto las banderas de interfaz temporal.
17. Encontrar renderizaciones innecesarias sin adivinar
Causas comunes: que los padres pasen literales de objetos/matrices/funciones nuevos, que el cambio de contexto vuelva a renderizar a todos los consumidores, o que el estado se mantenga en un nivel demasiado alto. No intente adivinar; utilice el Profilador de React DevTools, grabe una interacción y vea qué propiedades cambiaron. Las soluciones suelen consistir en bajar el nivel del estado o dividir los componentes para que los subárboles costosos dejen de aprovecharse de actualizaciones económicas, en lugar de recurrir primero a useMemo. Los profiladores convierten la sensación de lentitud en una explicación concreta sobre los padres y propiedades que se puede corregir.
18. SSR en comparación con CSR
CSR envía una estructura HTML ligera junto con JavaScript; el navegador construye la página después de la descarga: es rápido para servirla, pero más lento para mostrarla de manera útil, y históricamente ha sido menos efectivo para el SEO hasta que se ejecuta el JavaScript. SSR envía HTML por cada solicitud y luego hidrata la página al agregar listeners: ofrece una mejor visualización inicial y un mejor rendimiento en SEO, pero requiere más trabajo del servidor. Next.js y otras herramientas añaden generación estática y transmisión en tiempo real, pero el equilibrio fundamental sigue siendo entre el tiempo de respuesta y el SEO por un lado, y el costo y la complejidad del servidor por otro. Decir que “SSR es siempre mejor” sin mencionar ese equilibrio constituye una respuesta débil en una entrevista.
19. Incompatibilidades en la hidratación y cómo ocurren
Hydration conecta a React con el HTML del servidor sin descartar la marcaje. Los desajustes ocurren cuando el HTML del servidor difiere de la primera renderización en el cliente: uso de Date.now() o Math.random() en la renderización, verificaciones con window que difieren en el servidor, o extensiones que inyectan nodos. React emite advertencias intensas y vuelve a renderizar frecuentemente en el cliente para recuperarse, lo que implica trabajo adicional además de una aparición visible de contenido incorrecto. El patrón preventivo habitual consiste en proteger las API exclusivas del navegador detrás de useEffect o componentes específicos.
20. Por qué React envuelve los eventos nativos en SyntheticEvent
El SyntheticEvent de React normaliza las peculiaridades entre navegadores (de modo que onChange funcione de manera consistente) y, históricamente, utilizaba la delegación de eventos a nivel raíz en lugar de un receptor nativo por nodo. React 17+ delega los eventos al contenedor raíz de la aplicación en lugar de a document, pero la idea se mantiene. Antes se empleaba el agrupamiento de objetos de evento para reutilizarlos y así que los accesos asíncronos mostraran null; este método ya no existe desde React 17, pero conocer la capa entre el evento del navegador y el manejador sigue indicando su nivel de profundidad. Mencionar que e.nativeEvent sigue existiendo en el fondo demuestra que se comprende que la abstracción es un envoltorio, y no un reemplazo del modelo de eventos DOM.
Qué realmente valoran las entrevistas
Las respuestas sólidas en una entrevista explican el problema, los puntos críticos y cómo solucionarías las dificultades de un compañero de equipo, no una definición memorizada. A los entrevistadores les interesa menos si puedes definir useEffect y más si los cierres obsoletos, la falta de limpieza o errores en las dependencias te han afectado y puedes explicar por qué. Reproduce esos errores en un entorno aislado antes de la entrevista; las experiencias reales demuestran comprensión. Las definiciones te ayudan a superar el primer minuto; los compromisos y las historias de fracaso guían el resto de la conversación.
Mantén una breve hoja de referencia personal con los errores que hayas corregido: efectos obsoletos, teclas defectuosas, incoherencias en la hidratación, etc., y practica explicar cada uno en menos de un minuto. Esa preparación es mejor que estudiar a última hora las firmas de la API, y te permite ofrecer ejemplos concretos cuando el entrevistador pida un caso de tu trabajo. Asocia cada ejemplo con la solución que hayas implementado para que tu respuesta se centre en el juicio técnico, no solo en las dificultades enfrentadas. Ese toque final es lo que distingue a quienes solo “leen los documentos” de aquellos que “operan esta tecnología bajo presión”.
Lecturas relacionadas
- Respuestas a entrevistas sobre React y JavaScript que muestran profundidad real — Explora respuestas más sólidas y detalladas a preguntas comunes en entrevistas de React y JavaScript, desde el Virtual DOM hasta el diseño de sistemas, que demuestran un mayor juicio técnico.