Cuando el estado del componente es suficiente en pantallas móviles. Usa useReducer cuando varios campos se actualizan juntos - pasos de pago, asistentes de incorporación y formularios con mucha validación. Mantén las respuestas de API en TanStack Query; los reducers poseen solo transiciones de UI de cliente.
dispatch de useReducer es estable durante la vida útil del componente - omítelo de los arrays de dependencias de useEffect. Lo mismo aplica para setState de useState. Las reglas de lint react-hooks documentan esto.
Mantén wizardReducer en el mismo archivo que OnboardingWizard hasta que una segunda pantalla necesite transiciones idénticas. Promuévelo a features/onboarding/wizardReducer.ts solo en reutilización - no de manera preventiva.
Muchas llamadas useState no relacionadas - Cinco booleanos para un formulario significa actualizaciones perdidas. Solución: Un useReducer o React Hook Form.
Mutando estado dentro del reducer - state.items.push(x) rompe React. Solución: Devuelve nuevos objetos: { ...state, items: [...state.items, x] }.
Efectos secundarios del reducer - Obtener dentro de switch dificulta las pruebas. Solución: Efectos secundarios en manejadores de eventos; reducer se mantiene puro.
Almacenar listas de API en reducer - Duplica el caché de TanStack Query. Solución: Query para datos del servidor; reducer para borrador solo de UI.
Elevar reducer demasiado alto - El estado del asistente en Context raíz re-renderiza la aplicación. Solución: Mantén el reducer en la pantalla del asistente hasta que otra ruta realmente lo necesite.
Falta el caso default - La exhaustividad de TypeScript ayuda; las acciones desconocidas en tiempo de ejecución deben devolver state.
Actualizaciones funcionales con reducer - Los reducers ya reciben el estado anterior - no anides patrones setState dentro.
¿useState o useReducer para un formulario de inicio de sesión?
Dos campos (correo electrónico, contraseña) - useState está bien. Si agregas remember-me, paso MFA y validación en línea, cambia a useReducer o Hook Form.
¿Puedo usar useReducer con Context?
Sí - useReducer en un proveedor es el patrón global integrado. Divide contextos o Zustand cuando los consumidores se re-renderizan demasiado a menudo - ver Context Without Storms.
¿useReducer reemplaza Redux?
Solo para estado de UI local o pequeño compartido. Redux Toolkit aún gana para dominios multi-característica auditados y DevTools a escala - ver Redux Toolkit.
¿Cómo pruebo un reducer?
Exporta wizardReducer y prueba unitariamente acciones sin renderizar:
expect(wizardReducer(initial, { type: "next" })).toEqual({ ...initial, error: "El nombre debe tener al menos 2 caracteres" });
¿Debería submitting estar en el reducer?
Mantén submitting como useState o deriva de isPending de useMutation. El estado asincrónico es un efecto secundario, no una transición pura.
¿Qué hay sobre useActionState de React 19?
useActionState se dirige a Server Actions en web. Las aplicaciones móviles de Expo usan useReducer + useMutation de TanStack Query para envíos en red.
¿Cuántos hooks useState es demasiados?
Regla de oro: más de cuatro valores relacionados en una pantalla - considera un reducer o un hook personalizado envolviéndote el estado.
¿Puedo usar immer con useReducer?
Sí vía useImmerReducer de use-immer. Zustand + middleware immer es más común para almacenes globales - ver Zustand.
¿Cómo interactúan los asistentes con Expo Router?
Mantén el índice de paso en el estado del reducer para transiciones animadas. Para el progreso compartible, refleja el paso en router.setParams({ step: "2" }) - la URL es UX opcional, el reducer es la fuente de verdad durante la sesión.
¿Por qué no poner todo en un gran objeto useState?
setState({ ...s, email }) funciona hasta que dos actualizaciones se cotejan incorrectamente u olvidas un campo. Los reducers fuerzan nombres de acción explícitos - más fácil de registrar y probar.
¿Cómo se relaciona esto con contenedor/presentador?
El contenedor mantiene useReducer / useState; el presentador recibe solo props y callbacks - ver container-presenter en móvil.
¿Rendimiento en listas largas?
El estado del reducer en un padre de una FlatList de 500 filas re-renderiza todas las filas. Mueve los datos de la lista a Query; mantén la selección en reducer con extraData o memoización a nivel de fila.