Inicio > Cursos > React Native > Proyecto: App de Notas
React NativeReact Native AvanzadoLección 8 de 14

Proyecto: App de Notas

Este proyecto integra todos los conceptos del curso en una app funcional: navegación con React Navigation (lista de notas + pantalla de detalle/edición), estado global con Zustand para las notas en memoria, persistencia con AsyncStorage para que las notas sobrevivan al cerrar la app, FlatList para mostrar la lista eficientemente, y animaciones de entrada con Reanimated para una experiencia pulida.

El proyecto te enseña a estructurar una app React Native real: separar la lógica en custom hooks y stores de Zustand, crear componentes reutilizables para las tarjetas de notas, manejar el teclado en iOS/Android (KeyboardAvoidingView), y hacer el texto editable inline. Estos patrones son los mismos que usarías en apps de producción. Una vez terminado, tendrás una base sólida para construir tu propia app mobile.

// store/notasStore.js
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
import AsyncStorage from "@react-native-async-storage/async-storage";

export const useNotasStore = create(
  persist(
    (set, get) => ({
      notas: [],
      agregar: (titulo, contenido) => set(state => ({
        notas: [
          ...state.notas,
          { id: Date.now(), titulo, contenido, fecha: new Date().toISOString() }
        ]
      })),
      eliminar: (id) => set(state => ({
        notas: state.notas.filter(n => n.id !== id)
      })),
      buscar: (query) => get().notas.filter(n =>
        n.titulo.toLowerCase().includes(query.toLowerCase())
      ),
    }),
    { name: "notas", storage: createJSONStorage(() => AsyncStorage) }
  )
);

// screens/ListaNotas.jsx
export function ListaNotas({ navigation }) {
  const { notas, eliminar } = useNotasStore();
  const [busqueda, setBusqueda] = useState("");
  const notasFiltradas = notas.filter(n =>
    n.titulo.toLowerCase().includes(busqueda.toLowerCase())
  );
  
  return (
    <View style={styles.container}>
      <TextInput
        placeholder="Buscar notas..."
        value={busqueda}
        onChangeText={setBusqueda}
        style={styles.buscador}
      />
      <FlatList
        data={notasFiltradas}
        keyExtractor={n => String(n.id)}
        renderItem={({ item }) => (
          <TouchableOpacity
            style={styles.nota}
            onPress={() => navigation.navigate("EditarNota", { id: item.id })}
            onLongPress={() => eliminar(item.id)}
          >
            <Text style={styles.tituloNota}>{item.titulo}</Text>
            <Text style={styles.fecha}>{new Date(item.fecha).toLocaleDateString()}</Text>
          </TouchableOpacity>
        )}
      />
      <TouchableOpacity
        style={styles.fab}
        onPress={() => navigation.navigate("NuevaNota")}
      >
        <Text style={styles.fabTexto}>+</Text>
      </TouchableOpacity>
    </View>
  );
}
Consejo📌 El FAB (Floating Action Button) con position: "absolute", bottom: 24, right: 24 es un patrón UX muy común en apps móviles.
← Animaciones con ReanimatedCámara y Galería con Expo →

Practica esta lección

Resuelve los ejercicios del curso de React Native en la app, gratis y con corrección automática.

Empezar a practicar