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
useStatepara estado local simple - Usa
Contextpara 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