NativeCraft

React Native CLI

React Native 0.78.2TypeScript 5.0.4Redux 5.0.1React Navigation 7.0

Project Overview

A modern, production-ready React Native boilerplate with TypeScript support, focusing on best practices, scalability, and developer experience. This boilerplate includes authentication flows, theming support, RTL handling, and a robust project structure.

Features

  • ๐Ÿ” Authentication Flow: Complete login and OTP verification using @twotalltotems/react-native-otp-input
  • ๐ŸŒ“ Theme Support: Dynamic light/dark theme switching with context
  • ๐ŸŒ Multi-language Support: RTL/LTR with i18next integration
  • ๐Ÿ“ฑ Responsive Design: Adapts to different screen sizes with proper scaling
  • ๐Ÿงฉ Modular Architecture: Clean and maintainable code structure
  • ๐Ÿ”„ State Management: Redux Toolkit with proper action handling
  • ๐ŸŽจ SVG Support: Vector graphics with react-native-svg and transformer
  • ๐Ÿ”’ Secure Storage: Encrypted storage with rn-secure-storage
  • ๐Ÿ’ซ Animations: Smooth animations with react-native-reanimated
  • ๐Ÿš€ Fast Development: Hot reloading and developer tools
  • ๐Ÿ›ก๏ธ Type Safety: Full TypeScript integration
  • ๐ŸŽฏ Navigation: React Navigation 7 with bottom tabs and native stack

Project Architecture

.
โ”œโ”€โ”€ android/                  # Android native code
โ”œโ”€โ”€ ios/                     # iOS native code
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ assets/             # Images, fonts, etc.
โ”‚   โ”œโ”€โ”€ components/         # Reusable UI components
โ”‚   โ”œโ”€โ”€ config/             # App configuration
โ”‚   โ”œโ”€โ”€ context/            # React Context providers
โ”‚   โ”œโ”€โ”€ hooks/              # Custom React hooks
โ”‚   โ”œโ”€โ”€ lang/               # i18n translations
โ”‚   โ”œโ”€โ”€ models/             # TypeScript interfaces
โ”‚   โ”œโ”€โ”€ navigation/         # Navigation setup
โ”‚   โ”œโ”€โ”€ redux/              # State management
โ”‚   โ”œโ”€โ”€ screens/            # Screen components
โ”‚   โ”œโ”€โ”€ styles/             # Global styles
โ”‚   โ”œโ”€โ”€ typings/           # Global TypeScript types
โ”‚   โ””โ”€โ”€ utils/             # Utility functions
โ”œโ”€โ”€ patches/                # Patch files for dependencies
โ”œโ”€โ”€ vendor/                # Vendor files
โ”œโ”€โ”€ .eslintrc.js           # ESLint configuration
โ”œโ”€โ”€ .prettierrc.js         # Prettier configuration
โ”œโ”€โ”€ babel.config.js        # Babel configuration
โ”œโ”€โ”€ metro.config.js        # Metro bundler configuration
โ”œโ”€โ”€ tsconfig.json          # TypeScript configuration
โ””โ”€โ”€ package.json           # Project dependencies

Technology Stack

Core

  • React Native: v0.78.2
  • TypeScript: v5.0.4
  • React: v19.0.0

State Management & Data Flow

  • Redux: v5.0.1
  • React Redux: v9.2.0
  • Redux Toolkit: v2.6.1

Navigation

  • @react-navigation/native: v7.1.5
  • @react-navigation/native-stack: v7.3.9
  • @react-navigation/bottom-tabs: v7.3.9

UI & Animations

  • react-native-reanimated: v3.17.2
  • react-native-svg: v15.11.2
  • react-native-modal: v14.0.0-rc.1
  • react-native-bootsplash: v6.3.4

Core Concepts and Implementation

Theme System (Dark/Light)

The app uses a Context-based theming system that allows for seamless switching between light and dark modes:

// src/context/ThemeContext.tsx
import React, { createContext, useState, useEffect, useContext } from 'react';
import { secureStorage } from '@/utils/secureStorage';
import { Colors, ThemeType } from '@/styles/colors';

// Usage in components
const { theme, toggleTheme } = useTheme();
const colors = Colors[theme];

Key Features:

  • Theme persistence using Secure Storage
  • Dynamic theme switching with context API
  • Semantic color naming that adapts to current theme
  • Support for system theme detection

Using Theme Colors:

// Component example
import { useTheme } from '@/context/ThemeContext';
import { Colors } from '@/styles/colors';

const MyComponent = () => {
const { theme } = useTheme();
const colors = Colors[theme];

return (
<View style={{ backgroundColor: colors.background }}>
<Text style={{ color: colors.text }}>Hello World</Text>
</View>
);
};

Font Management

Fonts are loaded at application startup and made available through a centralized font family object:

// Font loading in App.tsx
const [loaded, error] = useFonts({
"Inter-Regular": require("./src/assets/fonts/Inter-Regular.ttf"),
"Inter-Bold": require("./src/assets/fonts/Inter-Bold.ttf"),
"Inter-Medium": require("./src/assets/fonts/Inter-Medium.ttf"),
"Inter-SemiBold": require("./src/assets/fonts/Inter-SemiBold.ttf"),
});

// Usage with fontFamily utility
import fontFamily from '@/styles/fontFamily';

const styles = StyleSheet.create({
title: {
fontFamily: fontFamily.bold,
fontSize: 18,
}
});

Font Family Structure:

// src/styles/fontFamily.ts
export default {
regular: 'Inter-Regular',
medium: 'Inter-Medium',
semiBold: 'Inter-SemiBold',
bold: 'Inter-Bold',
};

Internationalization (I18n)

The app supports multiple languages with full RTL layout support using i18next:

// src/lang/index.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import 'intl-pluralrules';
import en from './en.json';
import ar from './ar.json';

i18n
.use(initReactI18next)
.init({
resources: {
en: { translation: en },
ar: { translation: ar }
},
lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false
}
});

export default i18n;

Translation Files Structure:

// en.json
{
"LOGIN": "Login",
"WELCOME_MESSAGE": "Welcome to NativeCraft"
}

// ar.json
{
"LOGIN": "ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„",
"WELCOME_MESSAGE": "ู…ุฑุญุจู‹ุง ุจูƒ ููŠ NativeCraft"
}

Using Translations:

// With the TextComp wrapper component
<TextComp text="LOGIN" />

// With variable substitution
<TextComp text="HELLO_USER" values={{ name: user.name }} />

RTL Support:

// Custom hook for RTL detection
import { useTranslation } from 'react-i18next';

export default function useIsRTL() {
const { i18n } = useTranslation();
return i18n.language === 'ar';
}

// Usage in styles
const styles = StyleSheet.create({
container: {
flexDirection: isRTL ? 'row-reverse' : 'row',
textAlign: isRTL ? 'right' : 'left',
}
});

Reusable Components

The app uses a set of standardized components to ensure consistency:

TextComp - Text Component with i18n Support:

// Usage
<TextComp text="WELCOME" />
<TextComp isDynamic text="Hello World" /> // Direct text without translation

ButtonComp - Customizable Button:

// Usage
<ButtonComp 
text="LOGIN" 
onPress={handleLogin}
variant="primary" // or "secondary", "outline", etc.
isLoading={isLoading}
/>

TextInputComp - Custom Text Input:

// Usage
<TextInputComp
label="EMAIL"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
isPassword={false}
/>

HeaderComp - App Header:

// Usage
<HeaderComp 
title="PROFILE" 
showBack={true}
onBackPress={() => navigation.goBack()}
/>

WrapperContainer - Safe Area Wrapper:

// Usage
<WrapperContainer>
{/* Screen content */}
</WrapperContainer>

State Management with Redux

The app uses Redux Toolkit for centralized state management:

// Store setup
// src/redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers';

const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => 
getDefaultMiddleware({
serializableCheck: false,
}),
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;

Reducers Structure:

// src/redux/reducers/index.ts
import { combineReducers } from '@reduxjs/toolkit';
import authReducer from './authSlice';
import appReducer from './appSlice';

const rootReducer = combineReducers({
auth: authReducer,
app: appReducer,
});

export default rootReducer;

Actions Structure:

// src/redux/actions/index.ts
import * as authActions from './authActions';
import * as appActions from './appActions';

export default {
...authActions,
...appActions,
};

Using Redux in Components:

// In a component
import { useDispatch, useSelector } from 'react-redux';
import actions from '@/redux/actions';
import { RootState } from '@/redux/store';

const Component = () => {
const dispatch = useDispatch();
const { user } = useSelector((state: RootState) => state.auth);

const handleLogin = async () => {
await dispatch(actions.login(credentials));
};

return (/* Component JSX */);
};

API Integration

The app uses a centralized API service based on Axios:

// src/config/api.ts
import axios from 'axios';
import { API_BASE_URL } from '@/config/constants';

const apiInstance = axios.create({
baseURL: API_BASE_URL,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});

// Request interceptor
apiInstance.interceptors.request.use(
async (config) => {
// Add authorization token if available
const token = await getAuthToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);

// Response interceptor
apiInstance.interceptors.response.use(
(response) => response.data,
(error) => {
// Handle errors (401, 403, 500, etc.)
return Promise.reject(error);
}
);

export default apiInstance;

API Actions:

// src/redux/actions/authActions.ts
import apiInstance from '@/config/api';
import { createAsyncThunk } from '@reduxjs/toolkit';

export const login = createAsyncThunk(
'auth/login',
async (credentials, { rejectWithValue }) => {
try {
const response = await apiInstance.post('/auth/login', credentials);
return response;
} catch (error) {
return rejectWithValue(error.response?.data || 'Login failed');
}
}
);

Secure Local Storage

The app uses Expo's SecureStore for encrypted storage:

// src/utils/secureStorage.ts
import * as SecureStore from 'expo-secure-store';

// Storage keys
export const STORAGE_KEYS = {
AUTH_TOKEN: 'AUTH_TOKEN',
USER_DATA: 'USER_DATA',
LANGUAGE: 'LANGUAGE',
THEME: 'THEME',
} as const;

type StorageKeyType = keyof typeof STORAGE_KEYS;

export const secureStorage = {
async setItem(key: StorageKeyType, value: string) {
try {
await SecureStore.setItemAsync(STORAGE_KEYS[key], value);
} catch (error) {
console.error('Error storing value:', error);
}
},

async getItem(key: StorageKeyType) {
try {
return await SecureStore.getItemAsync(STORAGE_KEYS[key]);
} catch (error) {
console.error('Error retrieving value:', error);
return null;
}
},

async removeItem(key: StorageKeyType) {
try {
await SecureStore.deleteItemAsync(STORAGE_KEYS[key]);
} catch (error) {
console.error('Error removing value:', error);
}
},

// Helper for storing objects
async setObject(key: StorageKeyType, value: object) {
try {
const jsonValue = JSON.stringify(value);
await this.setItem(key, jsonValue);
} catch (error) {
console.error('Error storing object:', error);
}
},

// Helper for retrieving objects
async getObject(key: StorageKeyType) {
try {
const jsonValue = await this.getItem(key);
return jsonValue ? JSON.parse(jsonValue) : null;
} catch (error) {
console.error('Error retrieving object:', error);
return null;
}
},
};

SVG Integration

The app uses react-native-svg and react-native-svg-transformer for SVG support:

// In components
import Logo from '@/assets/icons/logo.svg';

const Component = () => {
return (
<View>
<Logo width={100} height={100} fill={colors.primary} />
</View>
);
};

Responsive Styling

The app uses a scaling utility for responsive dimensions:

// src/styles/scaling.ts
import { Dimensions } from 'react-native';

const { width, height } = Dimensions.get('window');

// Guideline sizes are based on standard ~5" screen mobile device
const guidelineBaseWidth = 350;
const guidelineBaseHeight = 680;

export const horizontalScale = (size: number) => (width / guidelineBaseWidth) * size;
export const verticalScale = (size: number) => (height / guidelineBaseHeight) * size;
export const moderateScale = (size: number, factor = 0.5) => 
size + (horizontalScale(size) - size) * factor;

Using Scale in Styles:

import { moderateScale } from '@/styles/scaling';

const styles = StyleSheet.create({
container: {
padding: moderateScale(16),
marginBottom: moderateScale(20),
},
title: {
fontSize: moderateScale(18),
},
});

Navigation Setup

The app uses React Navigation 7.x with a structured approach:

// src/navigation/Routes.tsx
import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AuthStack from './stacks/AuthStack';
import MainStack from './stacks/MainStack';
import { useSelector } from 'react-redux';
import { RootState } from '@/redux/store';

const Routes = () => {
const { isAuthenticated } = useSelector((state: RootState) => state.auth);

return (
<NavigationContainer>
{isAuthenticated ? <MainStack /> : <AuthStack />}
</NavigationContainer>
);
};

export default Routes;

Navigation Types:

// src/navigation/types.ts
export type AuthStackParamList = {
Login: undefined;
Signup: undefined;
OTPVerification: { email: string };
};

export type MainStackParamList = {
Home: undefined;
Profile: { userId: string };
Settings: undefined;
};

export type TabParamList = {
HomeTab: undefined;
ProfileTab: undefined;
SettingsTab: undefined;
};

Why This Architecture?

Modularity and Maintainability

This modular approach separates concerns clearly, making the codebase more maintainable:

  1. Component Reusability: UI components are reusable across screens
  2. Business Logic Separation: Redux actions/reducers separate business logic from UI
  3. Theming Abstraction: Theme is centralized and easily switchable
  4. Navigation Structure: Clear navigation hierarchy

Scalability

The architecture is designed to scale with your application:

  1. Feature Isolation: Add new features by adding new directories/modules
  2. Consistent Patterns: New developers can follow established patterns
  3. Performance Optimization: Easy to optimize specific components
  4. Testing: Components are isolated and easier to test

TypeScript Integration

TypeScript provides:

  1. Type Safety: Catch errors at compile time
  2. IDE Support: Better autocomplete and documentation
  3. Refactoring Confidence: Safer refactoring with type checking
  4. API Contract Enforcement: Interface definitions for API responses

Best Practices

Code Style

  • Use functional components with hooks
  • Keep components small and focused
  • Use descriptive variable and function names
  • Document complex logic with comments

Performance Considerations

  • Use React.memo for pure components
  • Use useCallback for event handlers
  • Use useMemo for expensive computations
  • Implement virtualized lists for long scrolling content

Security Best Practices

  • Store sensitive data in SecureStore
  • Use HTTPS for all API requests
  • Sanitize user inputs
  • Implement proper token refresh mechanism