A feature-rich todo application built with Expo and React Native, featuring local data persistence using SQLite and state management with Zustand.
- ✅ Create, read, update, and delete todos
- 📋 Organize todos into lists
- 💾 Local data persistence with SQLite
- 🔄 Real-time state management with Zustand
- 📱 Cross-platform support (iOS, Android, Web)
- 🎨 Clean and intuitive user interface
- 🔧 Type-safe implementation with TypeScript
- ⚡ Optimized performance with efficient database operations
- Frontend: React Native with Expo
- Navigation: Expo Router (file-based routing)
- State Management: Zustand
- Database: SQLite (expo-sqlite)
- Language: TypeScript
- UI Components: Custom components with Expo styling
todo-with-persistence/
├── app/ # Screens and navigation
│ ├── _layout.tsx # Root layout
│ ├── index.tsx # Home screen
│ ├── lists.tsx # Lists management
│ └── todos.tsx # Todo management
├── components/ # Reusable UI components
│ ├── Button.tsx
│ ├── Input.tsx
│ ├── LoadingSpinner.tsx
│ └── Modal.tsx
├── lib/ # Business logic and services
│ ├── database/ # Database setup and schema
│ ├── services/ # CRUD operations
│ ├── store/ # Zustand stores
│ ├── types/ # TypeScript types
│ └── utils/ # Utility functions
└── hooks/ # Custom React hooks
- Node.js (v18 or higher)
- npm or yarn
- Expo CLI (
npm install -g expo-cli)
-
Clone the repository
git clone <repository-url> cd todo-with-persistence
-
Install dependencies
npm install
-
Start the development server
npm start
-
Choose your platform:
- Press
ato open in Android emulator - Press
ito open in iOS simulator - Press
wto open in web browser - Scan the QR code with Expo Go app on your device
- Press
- Android:
npm run android - iOS:
npm run ios - Web:
npm run web
The app follows a layered architecture with clear separation of concerns:
- Presentation Layer: React components and screens in the
app/directory - Business Logic Layer: Services and utilities in the
lib/directory - Data Layer: SQLite database with schema definitions
- Database: SQLite for local persistence with proper schema and migrations
- State Management: Zustand stores for managing application state
- Services: Business logic for CRUD operations on todos and lists
- Validation: Input validation to ensure data integrity
- Error Handling: Comprehensive error handling for graceful failures
import { todoService } from "@/lib/services";
const newTodo = await todoService.createTodo({
title: "Buy groceries",
listId: "default",
isCompleted: false,
});import { listService } from "@/lib/services";
const newList = await listService.createList({
name: "Work Tasks",
isDefault: false,
});import { useTodoStore, useListStore } from "@/lib/store";
function TodoComponent() {
const { todos, loading, error } = useTodoStore();
const { currentList } = useListStore();
// Component logic here
}- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.