diciembre 21, 2025
18 min de lectura

Preguntas para Entrevistas de Desarrollador Senior React Native: Guía Completa

interview
career-advice
job-search
Preguntas para Entrevistas de Desarrollador Senior React Native: Guía Completa
Milad Bonakdar

Milad Bonakdar

Autor

Domina el desarrollo avanzado de React Native con preguntas esenciales para entrevistas que cubren la optimización del rendimiento, los módulos nativos, la gestión del estado, las pruebas, los patrones de arquitectura y las mejores prácticas multiplataforma para desarrolladores senior.


Introducción

Se espera que los desarrolladores Senior de React Native diseñen aplicaciones multiplataforma escalables, optimicen el rendimiento, integren módulos nativos y tomen decisiones arquitectónicas informadas. Este rol exige una profunda experiencia en React Native, gestión de estado, desarrollo nativo y la capacidad de resolver desafíos complejos de desarrollo móvil.

Esta guía completa cubre las preguntas esenciales de la entrevista para los Desarrolladores Senior de React Native, que abarcan conceptos avanzados de React, optimización del rendimiento, gestión de estado, módulos nativos, pruebas y patrones arquitectónicos. Cada pregunta incluye respuestas detalladas, evaluación de rareza y clasificaciones de dificultad.


React Avanzado & Hooks (5 Preguntas)

1. Explica useMemo y useCallback. ¿Cuándo deberías usarlos?

Respuesta: Ambos hooks optimizan el rendimiento memorizando valores/funciones.

  • useMemo: Memoriza valores calculados (cálculos costosos)
  • useCallback: Memoriza referencias de funciones (previene la recreación)
  • Cuándo usar: Solo cuando tienes problemas de rendimiento. La optimización prematura puede hacer que el código sea más difícil de leer.
import { useMemo, useCallback, useState } from 'react';

function ExpensiveComponent({ items, onItemClick }) {
  // useMemo - memoriza cálculo costoso
  const sortedItems = useMemo(() => {
    console.log('Sorting items...');
    return items.sort((a, b) => a.price - b.price);
  }, [items]); // Solo recalcula cuando los items cambian
  
  // useCallback - memoriza función
  const handleClick = useCallback((id) => {
    console.log('Item clicked:', id);
    onItemClick(id);
  }, [onItemClick]); // Solo recrea cuando onItemClick cambia
  
  return (
    <FlatList
      data={sortedItems}
      renderItem={({ item }) => (
        <ItemRow item={item} onClick={handleClick} />
      )}
    />
  );
}

// Componente hijo con React.memo
const ItemRow = React.memo(({ item, onClick }) => {
  console.log('Rendering item:', item.id);
  return (
    <TouchableOpacity onPress={() => onClick(item.id)}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

Rareza: Muy Común Dificultad: Media


2. ¿Qué es useRef y cuáles son sus casos de uso?

Respuesta: useRef crea una referencia mutable que persiste a través de los renders sin causar re-renders.

  • Casos de uso:
    • Acceder a elementos DOM/nativos
    • Almacenar valores mutables sin disparar re-render
    • Mantener valores previos
    • Almacenar timers/intervals
import { useRef, useEffect } from 'react';
import { TextInput, Animated } from 'react-native';

function FormComponent() {
  const inputRef = useRef(null);
  const previousValue = useRef('');
  const animatedValue = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    // Enfoca el input al montar
    inputRef.current?.focus();
  }, []);
  
  const handleChange = (text) => {
    console.log('Previous:', previousValue.current);
    console.log('Current:', text);
    previousValue.current = text;
  };
  
  const startAnimation = () => {
    Animated.timing(animatedValue, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  };
  
  return (
    <View>
      <TextInput ref={inputRef} onChangeText={handleChange} />
      <Animated.View style={{ opacity: animatedValue }}>
        <Text>Animated Content</Text>
      </Animated.View>
    </View>
  );
}

// Ejemplo de Timer
function Timer() {
  const intervalRef = useRef(null);
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(intervalRef.current);
  }, []);
  
  return <Text>{count}</Text>;
}

Rareza: Común Dificultad: Media


3. Explica los Custom Hooks y cuándo crearlos.

Respuesta: Los custom hooks extraen la lógica con estado reutilizable en funciones separadas.

  • Beneficios: Reutilización de código, separación de responsabilidades, pruebas más fáciles
  • Convención: Debe comenzar con "use"
// Custom hook para fetching de API
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
  }, [url]);
  
  return { data, loading, error };
}

// Custom hook para el manejo de formularios
function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  
  const handleChange = (name, value) => {
    setValues(prev => ({ ...prev, [name]: value }));
  };
  
  const validate = (validationRules) => {
    const newErrors = {};
    Object.keys(validationRules).forEach(field => {
      const rule = validationRules[field];
      if (rule.required && !values[field]) {
        newErrors[field] = `${field} es requerido`;
      }
    });
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };
  
  return { values, errors, handleChange, validate };
}

// Uso
function UserProfile() {
  const { data, loading, error } = useFetch('https://api.example.com/user');
  const { values, errors, handleChange, validate } = useForm({
    name: '',
    email: '',
  });
  
  if (loading) return <ActivityIndicator />;
  if (error) return <Text>Error: {error}</Text>;
  
  return <Text>{data.name}</Text>;
}

Rareza: Común Dificultad: Media


4. ¿Qué es React Context y cuándo deberías usarlo?

Respuesta: Context proporciona una forma de pasar datos a través del árbol de componentes sin el "prop drilling".

  • Casos de uso: Tema, autenticación, preferencias de idioma
  • Precaución: Puede causar re-renders innecesarios si no se usa con cuidado
import { createContext, useContext, useState } from 'react';

// Crea el context
const ThemeContext = createContext();
const AuthContext = createContext();

// Theme Provider
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Auth Provider
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const login = async (credentials) => {
    const user = await loginAPI(credentials);
    setUser(user);
  };
  
  const logout = () => {
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Custom hooks para el context
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

function useAuth() {
  return useContext(AuthContext);
}

// Uso
function App() {
  return (
    <ThemeProvider>
      <AuthProvider>
        <MainApp />
      </AuthProvider>
    </ThemeProvider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = useTheme();
  const { user } = useAuth();
  
  return (
    <TouchableOpacity
      style={{ backgroundColor: theme === 'light' ? '#fff' : '#333' }}
      onPress={toggleTheme}
    >
      <Text>{user ? `Hola, ${user.name}` : 'Invitado'}</Text>
    </TouchableOpacity>
  );
}

Rareza: Muy Común Dificultad: Media


5. Explica la diferencia entre useEffect y useLayoutEffect.

Respuesta: Ambos ejecutan side effects, pero en diferentes momentos:

  • useEffect: Se ejecuta de forma asíncrona después de que el render se pinta en la pantalla
  • useLayoutEffect: Se ejecuta sincrónicamente antes de pintar (bloquea las actualizaciones visuales)
  • Usa useLayoutEffect cuando: Necesitas medir el DOM o prevenir el parpadeo visual
import { useEffect, useLayoutEffect, useRef, useState } from 'react';

function MeasureComponent() {
  const [height, setHeight] = useState(0);
  const elementRef = useRef(null);
  
  // useLayoutEffect - mide antes de pintar
  useLayoutEffect(() => {
    if (elementRef.current) {
      const { height } = elementRef.current.measure((x, y, width, height) => {
        setHeight(height);
      });
    }
  }, []);
  
  // useEffect - después de pintar
  useEffect(() => {
    console.log('Component rendered');
  }, []);
  
  return (
    <View ref={elementRef}>
      <Text>Height: {height}</Text>
    </View>
  );
}

Rareza: Media Dificultad: Difícil


Gestión de Estado (4 Preguntas)

6. Explica Redux y sus principios básicos.

Respuesta: Redux es un contenedor de estado predecible para aplicaciones de JavaScript.

Loading diagram...
  • Principios básicos:
    • Única fuente de verdad (un solo store)
    • El estado es de solo lectura (despacha acciones para cambiar)
    • Los cambios se realizan con funciones puras (reducers)
// Tipos de acción
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// Creadores de acciones
const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { id: Date.now(), text, completed: false },
});

const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: id,
});

// Reducer
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, action.payload];
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
};

// Store
import { createStore } from 'redux';
const store = createStore(todosReducer);

// Componente de React Native
import { useSelector, useDispatch } from 'react-redux';

function TodoList() {
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => dispatch(toggleTodo(item.id))}>
            <Text style={{ textDecorationLine: item.completed ? 'line-through' : 'none' }}>
              {item.text}
            </Text>
          </TouchableOpacity>
        )}
      />
      <Button title="Add" onPress={() => dispatch(addTodo('New Task'))} />
    </View>
  );
}

Rareza: Muy Común Dificultad: Difícil


7. ¿Qué es Redux Toolkit y cómo simplifica Redux?

Respuesta: Redux Toolkit es la forma oficial recomendada de escribir lógica de Redux.

  • Beneficios:
    • Menos boilerplate
    • Immer incorporado para actualizaciones inmutables
    • Incluye Redux Thunk
    • Mejor soporte de TypeScript
import { createSlice, configureStore } from '@reduxjs/toolkit';

// Slice (combina acciones y reducer)
const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      // Immer permite código "mutante"
      state.push({
        id: Date.now(),
        text: action.payload,
        completed: false,
      });
    },
    toggleTodo: (state, action) => {
      const todo = state.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
  },
});

export const { addTodo, toggleTodo } = todosSlice.actions;

// Store
const store = configureStore({
  reducer: {
    todos: todosSlice.reducer,
  },
});

// Async thunk
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchTodos = createAsyncThunk(
  'todos/fetchTodos',
  async () => {
    const response = await fetch('https://api.example.com/todos');
    return response.json();
  }
);

const todosSlice = createSlice({
  name: 'todos',
  initialState: { items: [], loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchTodos.pending, (state) => {
        state.loading = true;
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.loading = false;
        state.items = action.payload;
      })
      .addCase(fetchTodos.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

Rareza: Común Dificultad: Media


8. ¿Cuáles son las alternativas a Redux para la gestión del estado?

Respuesta: Existen múltiples soluciones de gestión de estado:

  • Context API + useReducer: Incorporado, bueno para aplicaciones simples
  • MobX: Basado en observables, menos boilerplate
  • Zustand: Mínimo, basado en hooks
  • Recoil: Basado en átomos, por Facebook
  • Jotai: Átomos primitivos
// Ejemplo de Zustand
import create from 'zustand';

const useStore = create((set) => ({
  todos: [],
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: Date.now(), text, completed: false }],
  })),
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ),
  })),
}));

// Uso
function TodoList() {
  const { todos, addTodo, toggleTodo } = useStore();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => toggleTodo(item.id)}>
            <Text>{item.text}</Text>
          </TouchableOpacity>
        )}
      />
    </View>
  );
}

Rareza: Común Dificultad: Media


9. ¿Cómo manejas los side effects en Redux?

Respuesta: Usa middleware para operaciones asíncronas:

  • Redux Thunk: Funciones que retornan funciones
  • Redux Saga: Basado en generadores, más poderoso
  • Redux Observable: Basado en RxJS
// Redux Thunk
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_REQUEST' });
  
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const user = await response.json();
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
};

// Uso
dispatch(fetchUser(123));

// Redux Saga
import { call, put, takeEvery } from 'redux-saga/effects';

function* fetchUserSaga(action) {
  try {
    const user = yield call(fetch, `https://api.example.com/users/${action.payload}`);
    const data = yield call([user, 'json']);
    yield put({ type: 'FETCH_USER_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
}

function* watchFetchUser() {
  yield takeEvery('FETCH_USER_REQUEST', fetchUserSaga);
}

Rareza: Común Dificultad: Difícil


Optimización del Rendimiento (5 Preguntas)

10. ¿Cómo optimizas el rendimiento de FlatList?

Respuesta: Múltiples estrategias mejoran el desplazamiento de FlatList:

  1. Usa keyExtractor: Proporciona claves únicas
  2. getItemLayout: Omite la medición para elementos de altura fija
  3. removeClippedSubviews: Desmonta las vistas fuera de la pantalla (Android)
  4. maxToRenderPerBatch: Controla el tamaño del lote
  5. windowSize: Controla la ventana renderizada
  6. initialNumToRender: Elementos a renderizar inicialmente
  7. Memoriza renderItem: Previene re-renders innecesarios
import React, { memo, useCallback } from 'react';

const ITEM_HEIGHT = 80;

// Componente de item memorizado
const ListItem = memo(({ item, onPress }) => {
  return (
    <TouchableOpacity onPress={() => onPress(item.id)} style={{ height: ITEM_HEIGHT }}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

function OptimizedList({ data }) {
  const handlePress = useCallback((id) => {
    console.log('Pressed:', id);
  }, []);
  
  const renderItem = useCallback(({ item }) => (
    <ListItem item={item} onPress={handlePress} />
  ), [handlePress]);
  
  const keyExtractor = useCallback((item) => item.id.toString(), []);
  
  const getItemLayout = useCallback((data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  }), []);
  
  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      updateCellsBatchingPeriod={50}
      initialNumToRender={10}
      windowSize={5}
    />
  );
}

Rareza: Muy Común Dificultad: Media


11. ¿Qué es el puente de React Native y cómo afecta el rendimiento?

Respuesta: El puente es la capa de comunicación entre JavaScript y el código nativo.

  • Cómo funciona:
    • JavaScript se ejecuta en un hilo separado
    • Los módulos nativos se ejecutan en hilos nativos
    • El puente serializa los datos entre ellos (JSON)
  • Impacto en el rendimiento:
    • La comunicación del puente es asíncrona
    • Sobrecarga de serialización
    • Puede convertirse en un cuello de botella con la comunicación frecuente
  • Soluciones:
    • Minimiza los cruces del puente
    • Operaciones por lotes
    • Usa animaciones nativas (omite el puente)
    • Nueva Arquitectura (JSI) elimina el puente
// Mal - cruces frecuentes del puente
const BadAnimation = () => {
  const [position, setPosition] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setPosition(p => p + 1); // ¡Cruce del puente en cada frame!
    }, 16);
    return () => clearInterval(interval);
  }, []);
  
  return <View style={{ transform: [{ translateX: position }] }} />;
};

// Bien - animación nativa (sin puente)
const GoodAnimation = () => {
  const translateX = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    Animated.timing(translateX, {
      toValue: 100,
      duration: 1000,
      useNativeDriver: true, // ¡Se ejecuta en el hilo nativo!
    }).start();
  }, []);
  
  return <Animated.View style={{ transform: [{ translateX }] }} />;
};

Rareza: Común Dificultad: Difícil


12. ¿Cómo previenes re-renders innecesarios?

Respuesta: Múltiples técnicas previenen renders desperdiciados:

  1. React.memo: Memoriza componentes
  2. useMemo/useCallback: Memoriza valores/funciones
  3. Props de clave apropiadas: Ayuda a React a identificar los cambios
  4. Evita objetos/arrays inline: Crea nuevas referencias
  5. Divide los componentes: Componentes más pequeños y enfocados
// Mal - crea un nuevo objeto en cada render
function BadComponent() {
  return <ChildComponent style={{ margin: 10 }} />; // ¡Nuevo objeto!
}

// Bien - referencia estable
const styles = StyleSheet.create({
  container: { margin: 10 },
});

function GoodComponent() {
  return <ChildComponent style={styles.container} />;
}

// React.memo con comparación personalizada
const ExpensiveComponent = React.memo(
  ({ data, onPress }) => {
    console.log('Rendering ExpensiveComponent');
    return (
      <View>
        <Text>{data.name}</Text>
        <Button onPress={onPress} />
      </View>
    );
  },
  (prevProps, nextProps) => {
    // Comparación personalizada - solo re-renderiza si data.id cambió
    return prevProps.data.id === nextProps.data.id;
  }
);

// Divide los componentes para aislar los re-renders
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
  
  return (
    <View>
      {/* Solo re-renderiza cuando count cambia */}
      <CountDisplay count={count} />
      
      {/* Solo re-renderiza cuando text cambia */}
      <TextDisplay text={text} />
      
      <Button onPress={() => setCount(c => c + 1)} />
    </View>
  );
}

const CountDisplay = React.memo(({ count }) => <Text>{count}</Text>);
const TextDisplay = React.memo(({ text }) => <Text>{text}</Text>);

Rareza: Muy Común Dificultad: Media


13. ¿Cómo optimizas las imágenes en React Native?

Respuesta: La optimización de imágenes es crucial para el rendimiento:

  1. Redimensiona las imágenes: Usa dimensiones apropiadas
  2. Cachea las imágenes: Usa librerías como react-native-fast-image
  3. Carga diferida (Lazy loading): Carga las imágenes bajo demanda
  4. Carga progresiva: Muestra un placeholder primero
  5. Usa formato WebP: Mejor compresión
import FastImage from 'react-native-fast-image';

function OptimizedImage({ uri }) {
  return (
    <FastImage
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
      style={{ width: 200, height: 200 }}
    />
  );
}

// Carga progresiva de imágenes
function ProgressiveImage({ thumbnailUri, fullUri }) {
  const [imageLoaded, setImageLoaded] = useState(false);
  
  return (
    <View>
      <Image
        source={{ uri: thumbnailUri }}
        style={styles.image}
        blurRadius={imageLoaded ? 0 : 5}
      />
      <Image
        source={{ uri: fullUri }}
        style={[styles.image, { opacity: imageLoaded ? 1 : 0 }]}
        onLoad={() => setImageLoaded(true)}
      />
    </View>
  );
}

// Pre-fetching de imágenes
import { Image } from 'react-native';

const prefetchImages = async (urls) => {
  const promises = urls.map(url => Image.prefetch(url));
  await Promise.all(promises);
};

Rareza: Común Dificultad: Media


14. ¿Qué herramientas usas para el performance profiling?

Respuesta: Múltiples herramientas ayudan a identificar problemas de rendimiento:

  • React DevTools Profiler: Tiempos de render de componentes
  • Flipper: Herramienta de depuración y profiling
  • Performance Monitor: Monitor de FPS incorporado
  • Systrace: Traza de rendimiento de Android
  • Instruments: Perfilado de rendimiento de iOS
// Habilita el monitor de rendimiento en desarrollo
import { LogBox } from 'react-native';

if (__DEV__) {
  // Muestra el monitor de rendimiento
  require('react-native').unstable_enableLogBox();
}

// Mide el tiempo de renderizado de componentes
import { Profiler } from 'react';

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) {
  console.log(`${id} (${phase}) took ${actualDuration}ms`);
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MyComponent />
    </Profiler>
  );
}

// Seguimiento personalizado del rendimiento
const measurePerformance = (name, fn) => {
  const start = performance.now();
  const result = fn();
  const end = performance.now();
  console.log(`${name} took ${end - start}ms`);
  return result;
};

Rareza: Común Dificultad: Media


Módulos Nativos y Específicos de la Plataforma (4 Preguntas)

15. ¿Cómo creas un Módulo Nativo en React Native?

Respuesta: Los módulos nativos te permiten usar código específico de la plataforma.

// iOS (Objective-C) - CalendarManager.m
#import "CalendarManager.h"
#import <React/RCTLog.h>

@implementation CalendarManager

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  RCTLogInfo(@"Creating event %@ at %@", name, location);
}

@end

// Android (Java) - CalendarModule.java
package com.myapp;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class CalendarModule extends ReactContextBaseJavaModule {
  CalendarModule(ReactApplicationContext context) {
    super(context);
  }

  @Override
  public String getName() {
    return "CalendarManager";
  }

  @ReactMethod
  public void addEvent(String name, String location) {
    Log.d("CalendarModule", "Creating event " + name + " at " + location);
  }
}

// Uso de JavaScript
import { NativeModules } from 'react-native';

const { CalendarManager } = NativeModules;

function MyComponent() {
  const createEvent = () => {
    CalendarManager.addEvent('Meeting', 'Office');
  };
  
  return <Button title="Create Event" onPress={createEvent} />;
}

Rareza: Media Dificultad: Difícil


16. ¿Cómo manejas el código específico de la plataforma?

Respuesta: Múltiples enfoques para código específico de la plataforma:

  1. Módulo de plataforma: Verifica la plataforma en tiempo de ejecución
  2. Archivos específicos de la plataforma: .ios.js y .android.js
  3. Platform.select: Selecciona valores basados en la plataforma
import { Platform } from 'react-native';

// Módulo de plataforma
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 20 : 0,
  },
});

// Platform.select
const styles = StyleSheet.create({
  container: {
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.3,
      },
      android: {
        elevation: 4,
      },
    }),
  },
});

// Archivos específicos de la plataforma
// Button.ios.js
export default function Button() {
  return <Text>iOS Button</Text>;
}

// Button.android.js
export default function Button() {
  return <Text>Android Button</Text>;
}

// Uso - selecciona automáticamente el archivo correcto
import Button from './Button';

// Verificación de la versión de la plataforma
if (Platform.Version >= 21) {
  // Android API 21+
}

Rareza: Muy Común Dificultad: Fácil


17. ¿Qué es la Nueva Arquitectura (Fabric y TurboModules)?

Respuesta: La Nueva Arquitectura mejora el rendimiento de React Native:

  • Fabric: Nuevo sistema de renderizado
    • Layout síncrono
    • Mejor interop con vistas nativas
    • Seguridad de tipos
  • TurboModules: Nuevo sistema de módulos nativos
    • Carga diferida
    • JSI (JavaScript Interface) - comunicación directa en C++
    • Sin serialización del puente

Beneficios:

  • Inicio más rápido
  • Menor uso de memoria
  • Llamadas nativas síncronas
  • Mejor seguridad de tipos

Rareza: Media Dificultad: Difícil


18. ¿Cómo manejas el deep linking en React Native?

Respuesta: El deep linking permite abrir pantallas específicas desde URLs.

import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';

// Configura el deep linking
const linking = {
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Profile: 'profile/:id',
      Settings: 'settings',
    },
  },
};

function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

// Maneja los enlaces entrantes
useEffect(() => {
  const handleUrl = ({ url }) => {
    console.log('Opened with URL:', url);
    // myapp://profile/123
  };
  
  // La aplicación se abrió desde un enlace
  Linking.getInitialURL().then(url => {
    if (url) handleUrl({ url });
  });
  
  // La aplicación ya está abierta, nuevo enlace
  const subscription = Linking.addEventListener('url', handleUrl);
  
  return () => subscription.remove();
}, []);

// Abre la URL programáticamente
const openURL = async (url) => {
  const supported = await Linking.canOpenURL(url);
  if (supported) {
    await Linking.openURL(url);
  }
};

Rareza: Común Dificultad: Media


Pruebas (3 Preguntas)

19. ¿Cómo pruebas los componentes de React Native?

Respuesta: Usa librerías de pruebas como Jest y React Native Testing Library.

import { render, fireEvent, waitFor } from '@testing-library/react-native';
import Counter from './Counter';

describe('Counter', () => {
  it('renders initial count', () => {
    const { getByText } = render(<Counter />);
    expect(getByText('Count: 0')).toBeTruthy();
  });
  
  it('increments count when button pressed', () => {
    const { getByText, getByTestId } = render(<Counter />);
    const button = getByTestId('increment-button');
    
    fireEvent.press(button);
    
    expect(getByText('Count: 1')).toBeTruthy();
  });
  
  it('fetches user data', async () => {
    const mockFetch = jest.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ name: 'John'
Newsletter subscription

Consejos de carrera semanales que realmente funcionan

Recibe las últimas ideas directamente en tu bandeja de entrada

Destácate ante los Reclutadores y Consigue el Trabajo de Tus Sueños

Únete a miles que transformaron sus carreras con currículums impulsados por IA que pasan el ATS e impresionan a los gerentes de contratación.

Comienza a crear ahora

Compartir esta publicación

Duplica tus Llamadas para Entrevistas

Los candidatos que adaptan sus currículums a la descripción del trabajo obtienen 2.5 veces más entrevistas. Usa nuestra IA para personalizar tu CV automáticamente para cada solicitud al instante.