TechLead
Lección 6 de 8

Gestion de Estado y Obtencion de Datos

useState, Context, Redux, React Query, y almacenamiento asincrono

Estado en React Native

La gestion de estado en React Native es identica a React web. Puedes usar useState, useReducer, Context API, o bibliotecas como Redux y Zustand.

useState y useReducer

import { useState, useReducer } from 'react';

// useState simple
function Contador() {
  const [cuenta, setCuenta] = useState(0);

  return (
    <View>
      <Text>Cuenta: {cuenta}</Text>
      <Button title="+" onPress={() => setCuenta(c => c + 1)} />
    </View>
  );
}

// useReducer para estado complejo
const initialState = { items: [], cargando: false };

function reducer(state, action) {
  switch (action.type) {
    case 'CARGAR':
      return { ...state, cargando: true };
    case 'EXITO':
      return { items: action.payload, cargando: false };
    default:
      return state;
  }
}

function Lista() {
  const [state, dispatch] = useReducer(reducer, initialState);
  // ...
}

Context API

import { createContext, useContext, useState } from 'react';

// Crear contexto
const AuthContext = createContext();

// Proveedor
export function AuthProvider({ children }) {
  const [usuario, setUsuario] = useState(null);

  const login = (datos) => setUsuario(datos);
  const logout = () => setUsuario(null);

  return (
    <AuthContext.Provider value={{ usuario, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Hook personalizado
export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth debe usarse dentro de AuthProvider');
  }
  return context;
}

// Uso en componente
function Perfil() {
  const { usuario, logout } = useAuth();

  if (!usuario) return <Text>No logueado</Text>;

  return (
    <View>
      <Text>Hola, {usuario.nombre}</Text>
      <Button title="Salir" onPress={logout} />
    </View>
  );
}

Obtencion de Datos con fetch

import { useState, useEffect } from 'react';

function ListaUsuarios() {
  const [usuarios, setUsuarios] = useState([]);
  const [cargando, setCargando] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const obtenerUsuarios = async () => {
      try {
        const respuesta = await fetch('https://api.ejemplo.com/usuarios');
        if (!respuesta.ok) throw new Error('Error de red');
        const datos = await respuesta.json();
        setUsuarios(datos);
      } catch (err) {
        setError(err.message);
      } finally {
        setCargando(false);
      }
    };

    obtenerUsuarios();
  }, []);

  if (cargando) return <ActivityIndicator />;
  if (error) return <Text>Error: {error}</Text>;

  return (
    <FlatList
      data={usuarios}
      keyExtractor={item => item.id.toString()}
      renderItem={({ item }) => <Text>{item.nombre}</Text>}
    />
  );
}

AsyncStorage - Almacenamiento Local

import AsyncStorage from '@react-native-async-storage/async-storage';

// Guardar datos
const guardarDatos = async (clave, valor) => {
  try {
    await AsyncStorage.setItem(clave, JSON.stringify(valor));
  } catch (e) {
    console.error('Error al guardar:', e);
  }
};

// Leer datos
const leerDatos = async (clave) => {
  try {
    const valor = await AsyncStorage.getItem(clave);
    return valor ? JSON.parse(valor) : null;
  } catch (e) {
    console.error('Error al leer:', e);
    return null;
  }
};

// Eliminar datos
const eliminarDatos = async (clave) => {
  try {
    await AsyncStorage.removeItem(clave);
  } catch (e) {
    console.error('Error al eliminar:', e);
  }
};

// Hook personalizado
function useAlmacenamiento(clave, valorInicial) {
  const [valor, setValor] = useState(valorInicial);

  useEffect(() => {
    leerDatos(clave).then(v => {
      if (v !== null) setValor(v);
    });
  }, [clave]);

  const guardar = async (nuevoValor) => {
    setValor(nuevoValor);
    await guardarDatos(clave, nuevoValor);
  };

  return [valor, guardar];
}

Mejores Practicas

  • Usa useState para estado local simple
  • Usa Context para estado global ligero (auth, tema)
  • Considera Redux/Zustand para apps grandes y complejas
  • Usa React Query o SWR para cache de datos del servidor
  • AsyncStorage es asincrono - siempre usa async/await