Welcome to your personalized React Native learning platform! This repo is designed to teach you React Native by building a real personal budgeting app based on the envelope budgeting system.
This is both:
- A comprehensive learning curriculum with 28 structured lessons
- A real app you'll build (envelope budget tracker)
- A fundable business ready for app store deployment
By the end, you'll have mastered React Native AND built a complete, professional app ready to launch!
npm installnpm start
# Press 'w' for web, 'i' for iOS, or 'a' for AndroidStart with Lesson 01: JSX and Components
π View Full Curriculum
Phase 1: Core Concepts (Days 1-7) β AVAILABLE NOW
- Lesson 01: JSX and Components
- Lesson 02: Props and Composition
- Lesson 03: State with useState
- Lesson 04: Lists and Keys
- Lesson 05: Styling in React Native
- Lesson 06: Navigation Basics
- Lesson 07: Forms and Input Handling
Phase 2: Data & APIs (Days 8-14) π§ Coming Soon
- State management with Zustand
- Data persistence with AsyncStorage
- Custom hooks
- Error handling
Phase 3: Advanced UI (Days 15-20) π§ Coming Soon
- Animations and gestures
- Charts and visualizations
- Dark mode and theming
Phase 4: Production Ready (Days 21-28) π§ Coming Soon
- Authentication
- Cloud sync
- App store deployment
A Digital Envelope Budget App featuring:
- π° Envelope budgeting system (allocate income to categories)
- πΈ Track expenses from each envelope
- π Beautiful, minimal interface
- π± Works 100% offline
- π¨ Professional design
Core Philosophy: Simplicity first, visual clarity, quick actions.
- π Curriculum: docs/curriculum-overview.md
- π‘ Learning Guide: docs/learning-guide.md
- π Lessons: docs/lessons/
- π Book Reference: "React Native in Action" by Nader Dabit
- Period Management: Monthly only (simple MVP)
- Initial Setup: Empty slate (users create envelopes)
- Unallocated Funds: Flexible (allocate anytime)
- Transaction Entry: Quick entry + full form
- Currency: USD only initially
learn-react-native/
βββ docs/
β βββ curriculum-overview.md
β βββ learning-guide.md
β βββ lessons/
β βββ 01-jsx-and-components.md
β βββ 02-props-and-composition.md
β βββ ... (28 lessons total)
βββ app/ # Your budget app screens
β βββ (tabs)/
β βββ envelope/
β βββ transaction/
βββ components/
β βββ budget/ # Budget-specific components
β βββ ui/ # Reusable UI components
βββ types/
β βββ budget.ts # TypeScript types
βββ constants/
β βββ Colors.ts
β βββ Design.ts # Design tokens
βββ stores/ # State management (Phase 2)
- Read lesson (15-20 min)
- Study examples (15-20 min)
- Complete exercise (30-60 min)
- Test your work (10-15 min)
- Review checkpoint (5 min)
Total: 1-2 hours per day
You can go faster or slower - learn at your own pace!
- β Checkpoints in every lesson
- β Common issues and solutions
- β Code examples you can copy
- β Step-by-step instructions
- β Book references for deeper learning
This is an Expo project created with create-expo-app, now configured as a React Native Learning Machine!
-
Install dependencies
npm install
-
Start the development server
npx expo start
Once the development server is running, you can test your app in multiple ways:
Press w in your terminal to open the app in your web browser.
- Install Expo Go from App Store (iOS) or Google Play (Android)
- Make sure your phone and computer are on the same WiFi network
- Open Expo Go and scan the QR code from your terminal
- Your app will open on your phone with live reload
Press i in your terminal to open the iOS Simulator.
Press a in your terminal to open the Android Emulator.
For testing with native modules:
npx expo run:ios # iOS device/simulator
npx expo run:android # Android device/emulatorFor the most reliable connection:
For iPhone:
- Connect your iPhone to your Mac via USB cable
- Trust the computer when prompted on your iPhone
- Run:
npx expo run:ios --device - Your app will install and open directly on your iPhone
For Android:
- Enable USB debugging on your Android device
- Connect via USB cable
- Run:
npx expo run:android --device - Your app will install and open directly on your Android device
If you have network issues with Expo Go:
npx expo start --tunnel- Make sure your phone and computer are on the same WiFi
- Try refreshing the Expo Go app (pull down to refresh)
- Check that the terminal shows "Using Expo Go" (not "Using development build")
- If you see "Using development build" but want to use Expo Go, make sure
expo-dev-clientis not installed - Remove it with:
npm uninstall expo-dev-client
- Try tunnel mode:
npx expo start --tunnel - Or use web version: press
win terminal
You can start developing by editing the files inside the app directory. This project uses file-based routing.
This project follows the Atomic Design methodology, organizing components into a hierarchical structure from simple to complex:
| Atomic Design Level | Components | Description | Examples from Your Project |
|---|---|---|---|
| Atoms | components/ui/ |
Basic building blocks, single responsibility, platform-specific | IconSymbol.tsx, TabBarBackground.tsx |
| Molecules | components/ (simple) |
Simple combinations of atoms with minimal logic | ThemedText.tsx, ThemedView.tsx, ExternalLink.tsx |
| Organisms | components/ (complex) |
Complex components with state, business logic, multiple molecules | Collapsible.tsx, ParallaxScrollView.tsx, HelloWave.tsx |
| Templates | app/ layout files |
Page layouts and routing structure | app/_layout.tsx, app/(tabs)/_layout.tsx |
| Pages | app/ content files |
Complete screens/pages | app/(tabs)/index.tsx, app/(tabs)/explore.tsx |
- IconSymbol.tsx - Basic icon primitive with platform-specific implementations
- TabBarBackground.tsx - Basic background primitive for tab navigation
- IconSymbol.ios.tsx - iOS-specific SF Symbols implementation
- ThemedText.tsx - Text component with theme support and typography variants
- ThemedView.tsx - View component with theme support
- ExternalLink.tsx - Link component with external URL handling
- HapticTab.tsx - Tab component with haptic feedback integration
- Collapsible.tsx - Complex component combining multiple molecules (ThemedText + ThemedView + IconSymbol) with state management
- ParallaxScrollView.tsx - Advanced scroll component with parallax effects and multiple child components
- HelloWave.tsx - Interactive component with animations, theming, and user interactions
- app/_layout.tsx - Root layout structure and navigation setup
- app/(tabs)/_layout.tsx - Tab navigation structure and styling
- app/(tabs)/index.tsx - Home screen with main content
- app/(tabs)/explore.tsx - Explore screen with additional features
- Reusability: Atoms can be reused across multiple molecules and organisms
- Maintainability: Clear separation of concerns makes debugging easier
- Scalability: Easy to add new components following the established pattern
- Consistency: Platform-specific implementations ensure consistent behavior across devices
- Type Safety: TypeScript integration provides compile-time error checking
The constants/ folder contains static values that remain unchanged throughout your application's lifecycle. These are used for configuration data, theme values, API endpoints, and other static information.
The constants/ folder is often broken down into sub-files to keep things organized. A typical structure would look something like this:
src/
βββ constants/
βββ api.ts // API endpoints, API keys, etc.
βββ colors.ts // App-wide color palette
βββ dimensions.ts // Dimensions for responsive design (e.g., header height)
βββ fonts.ts // Font families and sizes
βββ strings.ts // UI text, titles, button labels, etc.
βββ index.ts // A single point of export for all constants
export const BASE_URL = 'https://api.yourapp.com/v1';
export const API_KEY = 'your_super_secret_key';
export const ENDPOINTS = {
LOGIN: '/auth/login',
PRODUCTS: '/products',
USER_PROFILE: '/user',
};export const COLORS = {
primary: '#007BFF',
secondary: '#6c757d',
success: '#28a745',
error: '#dc3545',
background: '#f8f9fa',
text: '#212529',
};export const AppStrings = {
loginTitle: 'Welcome Back!',
loginButton: 'Log In',
registerButton: 'Create an Account',
loading: 'Loading...',
};By creating an index.ts file in your constants/ folder, you can export all your constants from a single file, making your imports cleaner:
src/constants/index.ts:
import * as Colors from './colors';
import * as Strings from './strings';
import * as Api from './api';
export {
Colors,
Strings,
Api
};Then, in any component where you need to use a constant, you can import it like this:
src/screens/LoginScreen.tsx:
import React from 'react';
import { View, Text, Button } from 'react-native';
import { Colors, Strings } from '../constants';
const LoginScreen = () => {
return (
<View style={{ backgroundColor: Colors.background }}>
<Text>{Strings.loginTitle}</Text>
<Button title={Strings.loginButton} color={Colors.primary} />
</View>
);
};Your project currently has a well-organized Colors.ts constant that supports both light and dark themes:
export const Colors = {
light: {
text: '#11181C',
background: '#fff',
tint: '#0a7ea4',
icon: '#687076',
tabIconDefault: '#687076',
tabIconSelected: '#0a7ea4',
},
dark: {
text: '#ECEDEE',
background: '#151718',
tint: '#fff',
icon: '#9BA1A6',
tabIconDefault: '#9BA1A6',
tabIconSelected: '#fff',
},
};- DRY Principle: Define once, use everywhere
- Easy Updates: Change in one place, affects entire app
- Type Safety: TypeScript catches errors
- Performance: No repeated object creation
- Testing: Easy to mock and test
- Maintainability: Clean, organized, and scalable codebase
- Group related constants (like your Colors object)
- Use descriptive names (
Colors.light.textnotc.l.t) - Export as objects for better organization
- Add TypeScript types for better IntelliSense
- Keep them in a dedicated folder (
constants/) - Use an index file for clean imports
This approach helps maintain a clean, organized, and scalable codebase, which is a hallmark of good software development practice.
Hooks are functions that allow you to "hook into" React state and lifecycle features from function components. They enable you to use state and other React features without writing a class component.
Hooks are functions that:
- Manage state (
useState,useReducer) - Handle side effects (
useEffect,useLayoutEffect) - Access context (
useContext) - Optimize performance (
useMemo,useCallback) - Create custom logic (custom hooks like
useThemeColor)
Your project contains custom hooks that handle theme management and color schemes:
export { useColorScheme } from 'react-native';Purpose: Detects the user's preferred color scheme (light/dark mode) on native platforms (iOS/Android).
How it works:
- Re-exports React Native's built-in
useColorSchemehook - Returns
'light','dark', ornullbased on system settings - Used by components to adapt to user's theme preference
export function useColorScheme() {
const [hasHydrated, setHasHydrated] = useState(false);
useEffect(() => {
setHasHydrated(true);
}, []);
const colorScheme = useRNColorScheme();
if (hasHydrated) {
return colorScheme;
}
return 'light';
}Purpose: Handles color scheme detection specifically for web platforms.
Key Features:
- Hydration Safety: Prevents hydration mismatches during server-side rendering
- Fallback: Returns
'light'as default until client-side hydration completes - Platform-Specific: Only used on web platforms (React Native Web)
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
const theme = useColorScheme() ?? 'light';
const colorFromProps = props[theme];
if (colorFromProps) {
return colorFromProps;
} else {
return Colors[theme][colorName];
}
}Purpose: Provides theme-aware color selection for components.
How it works:
- Accepts props: Optional light/dark color overrides
- Detects theme: Uses
useColorScheme()to get current theme - Prioritizes props: Uses prop colors if provided
- Falls back to constants: Uses
Colorsconstant as default - Type-safe: TypeScript ensures valid color names
// ThemedText.tsx
import { useThemeColor } from '@/hooks/useThemeColor';
export function ThemedText({ lightColor, darkColor, ...rest }) {
const color = useThemeColor(
{ light: lightColor, dark: darkColor },
'text'
);
return <Text style={{ color }} {...rest} />;
}// app/_layout.tsx
import { useColorScheme } from '@/hooks/useColorScheme';
export default function RootLayout() {
const colorScheme = useColorScheme();
// Use colorScheme to set theme
}- Reusability: Share logic between components
- Separation of Concerns: Keep components focused on UI
- Testing: Easy to test business logic separately
- Type Safety: TypeScript provides compile-time checks
- Platform Compatibility: Handle platform differences gracefully
- Start with "use":
useThemeColor,useColorScheme - Descriptive names: Clearly indicate what the hook does
- Platform suffixes:
.web.tsfor web-specific implementations - Consistent exports: Export as named functions
- Keep hooks focused: One responsibility per hook
- Handle platform differences: Use platform-specific files when needed
- Provide defaults: Always have fallback values
- Type everything: Use TypeScript for better IntelliSense
- Document purpose: Add comments explaining complex logic
- Test thoroughly: Hooks should be well-tested since they're reused
This hook architecture provides a clean, maintainable way to handle theme management across your React Native application.
Understanding the folder structure is crucial for maintaining a clean and scalable React Native application. Here's the recommended project structure:
my-app/
βββ app/ // All of your routes and screen components go here
β βββ (tabs)/
β β βββ index.tsx
β β βββ explore.tsx
β βββ _layout.tsx
β βββ +not-found.tsx
β βββ ...
βββ assets/ // Your images, fonts, and other static files
βββ components/ // Reusable UI components (buttons, cards, etc.)
βββ hooks/ // Your custom React hooks (useAuth, useTheme, etc.)
βββ state/ // Your global state management files (context or Zustand)
βββ utils/ // Utility functions and constants
βββ types/ // All of your TypeScript types and interfaces
βββ package.json
βββ ...
- File-based routing with Expo Router
_layout.tsx- Root layout and navigation structure(tabs)/- Tab-based navigation screens+not-found.tsx- 404 error page- Other route files - Additional screens and nested routes
- Images - Icons, logos, backgrounds
- Fonts - Custom typography files
- Other static files - Videos, audio, documents
- Atomic Design structure (atoms, molecules, organisms)
- Platform-specific components (
components/ui/) - Feature-specific components (forms, cards, modals)
useThemeColor.ts- Theme managementuseColorScheme.ts- Platform color detection- Custom business logic hooks (useAuth, useApi, etc.)
- Context providers - React Context for global state
- Zustand stores - Lightweight state management
- Redux slices - If using Redux Toolkit
- Helper functions - Date formatting, validation, etc.
- Constants - App-wide constants and configuration
- API utilities - HTTP client setup, interceptors
- Interface definitions - Component props, API responses
- Type declarations - Custom types and enums
- Global types - App-wide type definitions
- Scalability: Easy to add new features without cluttering
- Maintainability: Clear separation of concerns
- Team collaboration: Consistent structure across team members
- Code organization: Logical grouping of related functionality
- Type safety: Centralized TypeScript definitions
- Keep it flat: Avoid deeply nested folders when possible
- Group by feature: Organize related files together
- Use clear naming: Descriptive folder and file names
- Separate concerns: Keep UI, logic, and data separate
- Follow conventions: Stick to established patterns
This structure provides a solid foundation for building scalable React Native applications with clear organization and maintainable code.
The scripts/ folder contains utility scripts that automate common development tasks. These scripts help streamline your workflow and reduce manual, error-prone processes.
Scripts are Node.js files that automate repetitive tasks like:
- Project setup and initialization
- Code generation and scaffolding
- Build processes and deployment
- Testing and quality checks
- Project maintenance and cleanup
Your project includes a reset-project.js script that demonstrates how to create a clean, minimal project state from a starter template.
#!/usr/bin/env node
/**
* This script is used to reset the project to a blank state.
* It deletes or moves the /app, /components, /hooks, /scripts, and /constants
* directories to /app-example based on user input and creates a new /app directory
* with an index.tsx and _layout.tsx file.
*/Purpose: Resets a project to a clean, minimal state by removing example code and creating a blank slate for development.
This script is designed for starter templates, boilerplates, or frameworks that come with example code. When starting a new project, developers often want a clean slate rather than all the template examples.
This script is included in a React Native starter template that comes with:
- Example components and layouts
- Pre-defined folder structure
- Sample code demonstrating best practices
- Theme management examples
However, when building a real application, developers need a clean slate. This script provides an automated way to get that clean slate.
rl.question(
"Do you want to move existing files to /app-example instead of deleting them? (Y/n): ",
(answer) => {
const userInput = answer.trim().toLowerCase() || "y";
// Process user choice
}
);Purpose: Asks the user whether to preserve example code for reference or delete it entirely.
- 'Y' (default): Moves example code to
/app-exampledirectory for reference - 'N': Permanently deletes example code for a truly clean slate
const oldDirs = ["app", "components", "hooks", "constants", "scripts"];
const exampleDir = "app-example";
const newAppDir = "app";Process:
- Defines directories to be moved/deleted
- Creates new clean
appdirectory - Handles both move and delete operations
const indexContent = `import { Text, View } from "react-native";
export default function Index() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
);
}`;
const layoutContent = `import { Stack } from "expo-router";
export default function RootLayout() {
return <Stack />;
}`;Purpose: Creates minimal, working files to start development immediately.
#!/usr/bin/env nodeMakes the script executable from command line using Node.js.
- User Input Handling: Prompts for move vs delete decision
- Directory Processing: Loops through directories to move/delete
- New Structure Creation: Creates clean
appdirectory - Minimal Files: Generates basic
index.tsxand_layout.tsx
try {
// Script operations
} catch (error) {
console.error(`β Error during script execution: ${error.message}`);
}- Speed and Efficiency: Single command vs manual multi-step process
- Accuracy: Eliminates human error in repetitive tasks
- Standardization: Consistent setup across team members
- Automation: Reduces tedious manual work
- Documentation: Scripts serve as executable documentation
# Run the reset script
npm run reset-project
# Or run directly
node scripts/reset-project.jsAfter running:
- Choose whether to preserve example code
- Script creates clean project structure
- Start development with
npx expo start - Edit new files in
app/directory
- Clear Purpose: Each script should have a single, well-defined purpose
- User-Friendly: Provide clear prompts and feedback
- Error Handling: Graceful error handling with helpful messages
- Documentation: Include comments explaining complex logic
- Safety: Ask for confirmation before destructive operations
- Flexibility: Provide options (like move vs delete)
When creating custom scripts:
- Use shebang:
#!/usr/bin/env node - Handle errors: Wrap in try-catch blocks
- Provide feedback: Console logs for user guidance
- Make configurable: Accept parameters or prompts
- Document purpose: Clear comments and README entries
This script demonstrates how automation can significantly improve the developer experience by turning complex manual processes into simple, reliable commands.
For comprehensive information about implementing authentication in React Native applications, see our Authentication Guide.
This guide covers:
- Backend-as-a-Service solutions (Firebase, AWS Amplify, Auth0)
- Custom backend authentication with JWT tokens
- Social and passwordless authentication methods
- Best practices for secure authentication
- Implementation examples with code samples
- Recommended libraries for different authentication needs
For comprehensive React Native development best practices, see our Best Practices Guide.
This guide covers:
- Performance optimization (FlatList, memoization, asset management)
- Code reusability (atomic components, custom hooks, TypeScript)
- Navigation and routing (Expo Router best practices)
- Dependency management (updates, maintenance, cleanup)
- Testing and quality assurance (component testing, error boundaries)
- Security practices (secure storage, input validation)
- Accessibility (labels, color contrast, screen readers)
When you're ready, run:
npm run reset-projectThis command will move the starter code to the app-example directory and create a blank app directory where you can start developing.
To learn more about developing your project with Expo, look at the following resources:
- Expo documentation: Learn fundamentals, or go into advanced topics with our guides.
- Learn Expo tutorial: Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
Join our community of developers creating universal apps.
- Expo on GitHub: View our open source platform and contribute.
- Discord community: Chat with Expo users and ask questions.