# Top 30 Preguntas de Entrevista React: Guía Completa para Triunfar
> Las 30 preguntas de entrevista React más frecuentes en 2026. Respuestas detalladas, ejemplos de código y consejos para conseguir el puesto de desarrollador React.
- Published: 2026-01-31
- Updated: 2026-04-21
- Author: SharpSkill
- Tags: react interview, frontend interview, react questions, javascript, technical interview
- Reading time: 18 min
---
Las entrevistas técnicas de React evalúan la comprensión de los conceptos fundamentales, los patrones avanzados y las buenas prácticas. Esta guía reúne las 30 preguntas que aparecen con más frecuencia, con respuestas detalladas y ejemplos de código para preparar la entrevista con eficacia.
> **Consejo de preparación**
>
> Estas preguntas están organizadas por nivel de dificultad. Dominar los fundamentos antes de abordar los conceptos avanzados permite construir una preparación más sólida.
## Fundamentos de React
### 1. ¿Qué es el Virtual DOM y por qué lo usa React?
El Virtual DOM es una representación ligera en JavaScript del DOM real. React utiliza esta abstracción para optimizar las actualizaciones de la interfaz.
El proceso funciona en tres pasos: React crea primero una copia virtual del DOM, luego compara esa copia con la versión anterior cuando se producen cambios (algoritmo de diffing) y, por último, aplica solo las modificaciones necesarias en el DOM real (reconciliación).
```jsx
// Simplified example of the concept
// When state changes, React doesn't recreate the entire DOM
function Counter() {
const [count, setCount] = useState(0)
// Only the span containing count will be updated in the real DOM
// The rest of the component is untouched
return (
Counter
{count}
)
}
```
Este enfoque evita operaciones costosas sobre el DOM y permite actualizaciones eficientes incluso en interfaces complejas.
### 2. ¿Cuál es la diferencia entre componentes funcionales y de clase?
Los componentes funcionales son funciones de JavaScript que reciben props y devuelven JSX. Desde React 16.8, los hooks permiten usar estado y ciclo de vida dentro de componentes funcionales.
```jsx
// Functional component (recommended)
// More concise, easier to test, supports hooks
function Welcome({ name }) {
const [visits, setVisits] = useState(0)
useEffect(() => {
setVisits(v => v + 1)
}, [])
return
Hello {name}, visit #{visits}
}
// Class component (legacy)
// More verbose, requires this binding
class WelcomeClass extends React.Component {
state = { visits: 0 }
componentDidMount() {
this.setState(prev => ({ visits: prev.visits + 1 }))
}
render() {
return
}
}
```
Los componentes funcionales son hoy el estándar. Los componentes de clase siguen funcionando, pero ya no se recomiendan para proyectos nuevos.
### 3. ¿Cómo funciona JSX?
JSX es una extensión de sintaxis de JavaScript que permite escribir marcado dentro del código. No es HTML, sino JavaScript disfrazado.
```jsx
// What we write (JSX)
const element = (
Title
Paragraph
)
// What Babel compiles (pure JavaScript)
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Title'),
React.createElement('p', null, 'Paragraph')
)
```
Entre las diferencias con HTML destacan el uso de `className` en lugar de `class`, `htmlFor` en lugar de `for`, el camelCase para los atributos (`onClick`, `tabIndex`) y la obligación de cerrar las etiquetas autocerradas.
### 4. ¿Qué diferencia hay entre state y props?
Las props son datos que un componente padre pasa a un componente hijo. Son de solo lectura. El state es el estado interno del componente y se modifica mediante setters.
```jsx
// UserCard.jsx
// name and role are props (immutable)
function UserCard({ name, role }) {
// isExpanded is state (mutable)
const [isExpanded, setIsExpanded] = useState(false)
return (
{name}
{role}
{/* Modifying state triggers a re-render */}
{isExpanded && }
)
}
// Usage
```
La regla básica: las props fluyen hacia abajo (padre → hijo) y el state es local a cada componente.
### 5. ¿Por qué son importantes las keys en las listas?
Las keys permiten que React identifique qué elementos han cambiado, se han añadido o se han eliminado dentro de una lista. Sin keys únicas y estables, React puede comportarse de forma inesperada.
```jsx
// ❌ Bad practice: index as key
// Problem: if order changes, React loses tracking
{items.map((item, index) => (
))}
// ✅ Good practice: unique and stable identifier
{items.map(item => (
))}
// Concrete example of the problem with indices
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Create a project' }
])
// When deleting the first element with key={index}
// React will think element 0's content changed
// instead of understanding an element was removed
return (
{todos.map(todo => (
{todo.text}
))}
)
}
```
## React Hooks
### 6. Explica useState y sus errores comunes
`useState` gestiona el estado local dentro de un componente funcional. El setter acepta un valor o una función de actualización.
```jsx
// Declaration with initial value
const [count, setCount] = useState(0)
// ❌ Pitfall: multiple updates in the same cycle
function increment() {
setCount(count + 1) // count = 0, sets 1
setCount(count + 1) // count = 0 still, sets 1
setCount(count + 1) // count = 0 still, sets 1
// Final result: 1 (not 3)
}
// ✅ Solution: use the update function
function incrementCorrect() {
setCount(prev => prev + 1) // 0 → 1
setCount(prev => prev + 1) // 1 → 2
setCount(prev => prev + 1) // 2 → 3
// Final result: 3
}
// ❌ Pitfall: object mutation
const [user, setUser] = useState({ name: 'Alice', age: 25 })
user.age = 26 // Direct mutation, no re-render
// ✅ Solution: create a new object
setUser({ ...user, age: 26 })
// or
setUser(prev => ({ ...prev, age: 26 }))
```
### 7. ¿Cómo funciona useEffect con su array de dependencias?
`useEffect` ejecuta efectos secundarios después del render. El array de dependencias controla cuándo se dispara el efecto.
```jsx
// Executed on every render (rare, usually avoid)
useEffect(() => {
console.log('Render completed')
})
// Executed only on mount (equivalent to componentDidMount)
useEffect(() => {
console.log('Component mounted')
// Cleanup on unmount (equivalent to componentWillUnmount)
return () => {
console.log('Component unmounted')
}
}, [])
// Executed when userId changes
useEffect(() => {
async function fetchUser() {
const response = await fetch(`/api/users/${userId}`)
const data = await response.json()
setUser(data)
}
fetchUser()
}, [userId])
// ❌ Missing dependency - subtle bug
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1) // count is "captured" at its initial value
}, 1000)
return () => clearInterval(timer)
}, []) // count is missing from dependencies
// ✅ Fix with update function
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1) // No need for count in deps
}, 1000)
return () => clearInterval(timer)
}, [])
```
> **Regla ESLint**
>
> Mantener siempre activado `eslint-plugin-react-hooks` para detectar dependencias omitidas. Esta regla previene muchos errores difíciles de diagnosticar.
### 8. ¿Cuándo conviene usar useMemo y useCallback?
Estos hooks permiten memoizar valores y funciones para evitar cálculos o recreaciones innecesarias. Conviene no abusar de ellos.
```jsx
// useMemo: memoizes a computed value
function ProductList({ products, filter }) {
// Recalculated only if products or filter change
const filteredProducts = useMemo(() => {
console.log('Filtering...')
return products.filter(p => p.category === filter)
}, [products, filter])
return
{filteredProducts.map(p =>
{p.name}
)}
}
// useCallback: memoizes a function
function ParentComponent() {
const [count, setCount] = useState(0)
// Without useCallback, handleClick is recreated on every render
// Causing unnecessary re-renders of ExpensiveChild
const handleClick = useCallback((id) => {
console.log('Clicked:', id)
}, []) // Empty deps = stable function
return (
<>
{count}
{/* React.memo on ExpensiveChild for this to be effective */}
>
)
}
// ❌ Over-optimization: not needed here
const SimpleComponent = () => {
// This calculation is trivial, useMemo adds overhead
const doubled = useMemo(() => 2 * 2, [])
return {doubled}
}
```
Conviene recurrir a estos hooks solo cuando se identifica un problema real de rendimiento o cuando hay que estabilizar referencias que se pasan a componentes memoizados.
### 9. ¿Cómo funciona useRef y cuáles son sus casos de uso?
`useRef` crea una referencia mutable que persiste entre renders sin disparar un nuevo render cuando cambia.
```jsx
// Case 1: Access a DOM element
function TextInput() {
const inputRef = useRef(null)
const focusInput = () => {
inputRef.current.focus()
}
return (
<>
>
)
}
// Case 2: Store a mutable value without re-render
function Timer() {
const [seconds, setSeconds] = useState(0)
const intervalRef = useRef(null)
const start = () => {
// Store the interval ID to be able to stop it
intervalRef.current = setInterval(() => {
setSeconds(s => s + 1)
}, 1000)
}
const stop = () => {
clearInterval(intervalRef.current)
}
return (
{seconds}s
)
}
// Case 3: Keep the previous value
function usePrevious(value) {
const ref = useRef()
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}
```
### 10. Explica useContext y cuándo utilizarlo
`useContext` accede a un contexto de React sin necesidad de prop drilling. Resulta ideal para datos globales como el tema o el usuario autenticado.
```jsx
// 1. Create the context
const ThemeContext = createContext({
theme: 'light',
toggleTheme: () => {}
})
// 2. Create the provider
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
const toggleTheme = useCallback(() => {
setTheme(prev => prev === 'light' ? 'dark' : 'light')
}, [])
// Memoize the value to avoid unnecessary re-renders
const value = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme])
return (
{children}
)
}
// 3. Use the context
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext)
return (
)
}
// 4. Wrap the application
function App() {
return (
)
}
```
## Patrones avanzados
### 11. ¿Qué es un Higher-Order Component (HOC)?
Un HOC es una función que recibe un componente y devuelve otro mejorado. Se usa menos desde la llegada de los hooks, pero sigue presente en varias librerías.
```jsx
// HOC that adds logging
function withLogging(WrappedComponent) {
return function WithLogging(props) {
useEffect(() => {
console.log(`${WrappedComponent.name} mounted with props:`, props)
return () => {
console.log(`${WrappedComponent.name} unmounted`)
}
}, [])
return
}
}
// HOC that handles authentication
function withAuth(WrappedComponent) {
return function WithAuth(props) {
const { user, isLoading } = useAuth()
if (isLoading) return
if (!user) return
return
}
}
// Usage
const ProtectedDashboard = withAuth(Dashboard)
const LoggedButton = withLogging(Button)
```
### 12. Explica el patrón Render Props
El patrón Render Props permite compartir lógica entre componentes mediante una prop que es una función.
```jsx
// Component with render prop
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('mousemove', handleMove)
return () => window.removeEventListener('mousemove', handleMove)
}, [])
// Call the render function with data
return render(position)
}
// Usage
function App() {
return (
(
Position: {x}, {y}
)}
/>
)
}
// Modern version with custom hook (preferred)
function useMousePosition() {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('mousemove', handleMove)
return () => window.removeEventListener('mousemove', handleMove)
}, [])
return position
}
function App() {
const { x, y } = useMousePosition()
return
Position: {x}, {y}
}
```
### 13. ¿Cómo crear un hook personalizado?
Los hooks personalizados extraen y reutilizan lógica con estado entre varios componentes.
```jsx
// useLocalStorage.js
function useLocalStorage(key, initialValue) {
// Initialize with localStorage value or default
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch (error) {
console.error(error)
return initialValue
}
})
// Setter wrapper that syncs with localStorage
const setValue = useCallback((value) => {
try {
// Support update functions
const valueToStore = value instanceof Function ? value(storedValue) : value
setStoredValue(valueToStore)
window.localStorage.setItem(key, JSON.stringify(valueToStore))
} catch (error) {
console.error(error)
}
}, [key, storedValue])
return [storedValue, setValue]
}
// Usage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light')
const [fontSize, setFontSize] = useLocalStorage('fontSize', 16)
return (
setFontSize(Number(e.target.value))}
/>
)
}
```
### 14. ¿Qué es el patrón Compound Components?
Este patrón crea componentes que trabajan juntos de forma implícita, igual que las etiquetas `