https://github.com/linhnguyen-gt/new-react-native
✨ Best practice redux build with react native
https://github.com/linhnguyen-gt/new-react-native
hooks react-native redux redux-saga redux-toolkit typescript
Last synced: about 1 year ago
JSON representation
✨ Best practice redux build with react native
- Host: GitHub
- URL: https://github.com/linhnguyen-gt/new-react-native
- Owner: linhnguyen-gt
- Created: 2024-07-31T12:22:05.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-03-18T13:04:57.000Z (over 1 year ago)
- Last Synced: 2025-03-18T14:23:07.462Z (over 1 year ago)
- Topics: hooks, react-native, redux, redux-saga, redux-toolkit, typescript
- Language: TypeScript
- Homepage:
- Size: 2.73 MB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
🚀 New React Native Project
A powerful React Native boilerplate with production-ready configurations and best practices
### Core Libraries
### State Management & API
### UI & Styling
### Form & Validation
### Development & Testing
### Environment & Storage
### Development Tools
### Environment Support
## ✨ Features
- 🏗️ Built with TypeScript for type safety
- 📱 Cross-platform (iOS & Android) support
- 🔄 Redux + Redux Saga for state management
- 🎨 NativeWind for styling with Tailwind CSS
- 🛠️ Reactotron integration for debugging
- 🌐 Multi-environment support (Development, Staging, Production)
- 📦 Pre-configured folder structure
- 🔍 ESLint + Prettier for code quality
- 🎯 Gluestack UI components
- 🔐 Environment-specific configurations
## 🚀 Quick Start
### Prerequisites
Make sure you have the following installed:
- Node.js (v20+)
- Yarn
- React Native CLI
- Xcode (for iOS)
- Android Studio (for Android)
- Ruby (>= 2.6.10)
- CocoaPods
### Installation
### Clone the repository\*\*
```bash
git clone https://github.com/linhnguyen-gt/new-react-native
cd new-react-native
```
## 🔧 Environment Configuration
### Setup New Environment
First, you need to run the environment setup script:
```bash
# Using npm
npm run env:setup
# Using yarn
yarn env:setup
```
This script will:
1. Set up dotenv-vault (optional)
2. Create environment files for all environments:
- `.env` (Development environment)
- `.env.staging` (Staging environment)
- `.env.production` (Production environment)
3. Configure necessary environment variables
### Environment Files Structure
Each environment file contains:
```bash
# Required Variables
APP_FLAVOR=development|staging|production
VERSION_CODE=1
VERSION_NAME=1.0.0
API_URL=https://api.example.com
# Optional Variables (configured during setup)
GOOGLE_API_KEY=
FACEBOOK_APP_ID=
# ... other variables
```
### Using Different Environments
```bash
# Development (default)
yarn android
yarn ios
# Staging
yarn android:stg
yarn ios:stg
# Production
yarn android:pro
yarn ios:pro
```
### Setup Steps for New Project
### iOS Configuration
1. **Podfile Configuration**
Add this configuration block to your Podfile:
```ruby
# Configuration name environment mapping
project 'NewReactNative', {
'Debug' => :debug,
'Dev.Debug' => :debug,
'Dev.Release' => :release,
'Release' => :release,
'Staging.Debug' => :debug,
'Staging.Release' => :release,
'Product.Debug' => :debug,
'Product.Release' => :release
}
```
This configuration:
- Maps each build configuration to its corresponding mode (:debug or :release)
- Supports all environments (Dev, Staging, Product)
- Enables both Debug and Release builds for each environment
2. **Build Configurations**
Xcode should have these configurations set up:
- Staging.Debug/Release (Staging)
- Product.Debug/Release (Production)
- Debug/Release (Default)
3. **Version Management Script**
Add this script to Build Phase in Xcode:
.xcode.env.
```bash
# Determine APP_ENV based on CONFIGURATION
if [[ "${CONFIGURATION}" == *"Product"* ]]; then
export APP_ENV="production"
elif [[ "${CONFIGURATION}" == *"Staging"* ]]; then
export APP_ENV="staging"
fi
```
Build Phases -> Add Run Script -> Paste
```bash
# Get the environment from configuration name
echo "Debug: Raw CONFIGURATION value: ${CONFIGURATION}"
if [[ "${CONFIGURATION}" == *"Product"* ]]; then
ENV_FILE="${SRCROOT}/../.env.production"
echo "Debug: Matched Product configuration"
elif [[ "${CONFIGURATION}" == *"Staging"* ]]; then
ENV_FILE="${SRCROOT}/../.env.staging"
echo "Debug: Matched Staging configuration"
else
ENV_FILE="${SRCROOT}/../.env"
echo "Debug: Using default configuration"
fi
# Ensure INFOPLIST_FILE is set
if [ -z "$INFOPLIST_FILE" ]; then
echo "Error: INFOPLIST_FILE not set"
exit 0
fi
INFO_PLIST="${SRCROOT}/${INFOPLIST_FILE}"
echo "=== Environment Setup ==="
echo "CONFIGURATION: ${CONFIGURATION}"
echo "Using env file: ${ENV_FILE}"
echo "Info.plist path: ${INFO_PLIST}"
# Default values in case env file is missing
VERSION_CODE="1"
VERSION_NAME="1.0.0"
# Try to read from env file if it exists
if [ -f "$ENV_FILE" ]; then
echo "Reading from env file..."
# Read VERSION_CODE
VERSION_CODE_LINE=$(grep "^VERSION_CODE=" "$ENV_FILE" || echo "")
if [ ! -z "$VERSION_CODE_LINE" ]; then
VERSION_CODE=$(echo "$VERSION_CODE_LINE" | cut -d'=' -f2 | tr -d '"' | tr -d ' ')
fi
# Read VERSION_NAME
VERSION_NAME_LINE=$(grep "^VERSION_NAME=" "$ENV_FILE" || echo "")
if [ ! -z "$VERSION_NAME_LINE" ]; then
VERSION_NAME=$(echo "$VERSION_NAME_LINE" | cut -d'=' -f2 | tr -d '"' | tr -d ' ')
fi
else
echo "Warning: Environment file not found, using default values"
fi
echo "Using versions - Code: $VERSION_CODE, Name: $VERSION_NAME"
# Update Info.plist if it exists
if [ -f "$INFO_PLIST" ]; then
echo "Updating Info.plist..."
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION_CODE" "$INFO_PLIST" || true
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION_NAME" "$INFO_PLIST" || true
echo "Info.plist update completed"
else
echo "Warning: Info.plist not found at $INFO_PLIST"
fi
```
4. **Setup Steps for iOS**
- Copy the configuration block to your Podfile
- Run `pod install` to apply configurations
- Set up corresponding Build Configurations in Xcode
- Add the version management script to Build Phases
- Configure schemes to use appropriate configurations
### Android Configuration
1. **Product Flavors**
Add to app/build.gradle:
```gradle
flavorDimensions 'default'
productFlavors {
dev {
dimension 'default'
applicationId 'com.newreactnative'
resValue 'string', 'build_config_package', 'com.newreactnative'
def envFile = new File("${project.rootDir.parentFile}/.env")
if (envFile.exists()) {
def versionProps = getVersionFromEnv(envFile)
versionCode versionProps.code.toInteger()
versionName versionProps.name
}
}
staging {
dimension 'default'
applicationId 'com.newreactnative.stg'
resValue 'string', 'build_config_package', 'com.newreactnative'
def envFile = new File("${project.rootDir.parentFile}/.env.staging")
if (envFile.exists()) {
def versionProps = getVersionFromEnv(envFile)
versionCode versionProps.code.toInteger()
versionName versionProps.name
}
}
production {
dimension 'default'
applicationId 'com.newreactnative.production'
resValue 'string', 'build_config_package', 'com.newreactnative'
def envFile = new File("${project.rootDir.parentFile}/.env.production")
if (envFile.exists()) {
def versionProps = getVersionFromEnv(envFile)
versionCode versionProps.code.toInteger()
versionName versionProps.name
}
}
}
def getVersionFromEnv(File envFile) {
def versionCode = "1"
def versionName = "1.0.0"
envFile.eachLine { line ->
if (line.contains('=')) {
def (key, value) = line.split('=', 2)
if (key == "VERSION_CODE") versionCode = value?.trim()?.replaceAll('"', '')
if (key == "VERSION_NAME") versionName = value?.trim()?.replaceAll('"', '')
}
}
println "Reading from ${envFile.path}"
println "VERSION_CODE: ${versionCode}"
println "VERSION_NAME: ${versionName}"
return [code: versionCode, name: versionName]
}
```
### Update package.json Scripts
```json
{
"scripts": {
"android": "npx expo run:android --variant devDebug --app-id com.newreactnative",
"android:stg": "APP_ENV=staging && npx expo run:android --variant stagingDebug --app-id com.newreactnative.stg",
"android:pro": "APP_ENV=production && npx expo run:android --variant productionDebug --app-id com.newreactnative.production",
"ios": "npx expo run:ios",
"ios:stg": "APP_ENV=staging npx expo run:ios --scheme Staging --configuration Staging.Debug",
"ios:pro": "APP_ENV=production npx expo run:ios --scheme Pro --configuration Product.Debug"
}
}
```
### Update .gitignore
```bash
.env*
.flaskenv*
!.env.project
!.env.vault
# Environment files
.env
.env.*
!.env.example
!.env.vault
```
### Version Management
The setup automatically manages app versions based on environment files:
- VERSION_CODE: Used for internal build numbering
- VERSION_NAME: Used for display version in stores
### Important Notes
- Never commit `.env` files to git (they are automatically added to .gitignore)
- Always commit `.env.example` and `.env.vault` (if using dotenv-vault)
- Share vault credentials with your team members if using dotenv-vault
## 📁 Project Structure
```
src/
├── App.tsx # Main App component
├── Root.tsx # Root component with Redux Provider
├── apis/ # API integration
├── components/ # Reusable UI components
├── constants/ # Constants Keys
├── enums/ # TypeScript enums
├── helper/ # Helper functions
├── hooks/ # Custom React hooks
├── models/ # Models related to API
└── redux/ # Redux store configuration
├── actions/ # Redux actions
├── reducers/ # Redux reducers
├── sagas/ # Redux sagas
└── selectors/ # Redux selectors
├── screens/ # Screen components
├── services/ # Business logic and services
└── reactotron/ # Reactotron configuration
└── navigation/ # Navigation configuration
└── httpClient/ # Base API client configuration
└── store/ # Redux store configuration
└── types/ # TypeScript types
```
## 🛠️ Development Tools
### Reactotron
For debugging, the project includes Reactotron integration. To use it:
1. Install Reactotron on your development machine
2. Run the following command for Android:
```bash
yarn adb:reactotron
```
## 📝 Code Style
The project uses ESLint and Prettier for code formatting. Run linting with:
```bash
yarn lint # Check for issues
```
To fix linting errors automatically, use:
```bash
yarn lint:fix # Fix automatic issues
```