Lesson 15-React Native Advanced Application Development

Cross-Platform Compatibility

Handling Platform Differences (Platform Module, Conditional Rendering)

Basic Usage of Platform Module

import { Platform, StyleSheet } from 'react-native';

// Platform Detection
const isIOS = Platform.OS === 'ios';
const isAndroid = Platform.OS === 'android';

// Platform-Specific Values
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 50 : 20,
    paddingBottom: Platform.select({
      ios: 20,
      android: 10,
      default: 15 // Default Value (Optional)
    })
  }
});

Conditional Rendering of Components

import React from 'react';
import { View, Platform } from 'react-native';
import IOSpecificComponent from './IOSpecificComponent';
import AndroidSpecificComponent from './AndroidSpecificComponent';

const CrossPlatformComponent = () => (
  <View>
    {Platform.OS === 'ios' ? (
      <IOSpecificComponent />
    ) : (
      <AndroidSpecificComponent />
    )}
  </View>
);

Platform-Specific File Extensions

// File Naming Convention for Conditional Loading
MyComponent.ios.js  // iOS-Specific Implementation
MyComponent.android.js // Android-Specific Implementation
MyComponent.js       // Shared Base Implementation

// Import Directly; React Native Automatically Selects the Correct Platform File
import MyComponent from './MyComponent';

Cross-Platform Encapsulation of Native Modules

Unified Native Module Interface

// NativeBridge.js - Unified Encapsulation Layer
import { NativeModules, Platform } from 'react-native';

const { IOSModule, AndroidModule } = NativeModules;

export default {
  takePhoto() {
    if (Platform.OS === 'ios') {
      return IOSModule.takePhoto();
    } else {
      return AndroidModule.captureImage();
    }
  },
  getDeviceId() {
    // Unify Device ID Retrieval Across Platforms
    return Platform.OS === 'ios' 
      ? IOSModule.getIdentifier()
      : AndroidModule.getAndroidId();
  }
};

Android/iOS Native Module Examples

// Android Native Module (AndroidModule.java)
public class AndroidModule extends ReactContextBaseJavaModule {
    @ReactMethod
    public void captureImage(Promise promise) {
        // Android Camera Implementation
    }
    
    @ReactMethod
    public String getAndroidId() {
        return Settings.Secure.getString(getReactApplicationContext().getContentResolver(), 
            Settings.Secure.ANDROID_ID);
    }
}
// iOS Native Module (IOSModule.m)
@implementation IOSModule

RCT_EXPORT_METHOD(takePhoto:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    // iOS Camera Implementation
}

RCT_EXPORT_METHOD(getIdentifier:(RCTPromiseResolveBlock)resolve) {
    NSString *identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    resolve(identifier);
}

@end

Cross-Platform Compatibility of Third-Party Libraries

Library Compatibility Checklist

1. Check if the library's npm page explicitly states React Native support
2. Review GitHub Issues for known platform-related bugs
3. Verify if the library provides native code for both iOS and Android
4. Test the library in the following scenarios:
   - Different iOS versions (12+)
   - Different Android versions (8.0+)
   - Various device sizes and resolutions

Compatibility Encapsulation Example

// CameraUtils.js - Camera Functionality Compatibility Layer
import { Platform } from 'react-native';
import { launchCamera as iosLaunchCamera } from 'react-native-image-picker-ios';
import { launchCamera as androidLaunchCamera } from 'react-native-image-picker-android';

export const launchCamera = (options) => {
  if (Platform.OS === 'ios') {
    return iosLaunchCamera(options);
  } else {
    return androidLaunchCamera({
      ...options,
      // Android-Specific Configuration Conversion
      saveToPhotos: options.saveToCameraRoll // Parameter Name Mapping
    });
  }
};

Cross-Platform Testing Strategies

Test Matrix Design

| Test Type       | iOS Version Coverage | Android Version Coverage | Device Type       |
|-----------------|----------------------|--------------------------|-------------------|
| Unit Testing    | 12,14,15             | 8.0,9.0,10,11            | Emulator          |
| Integration Testing | 13,15            | 9.0,11                   | Real Device (iOS/Android) |
| E2E Testing     | 14,15                | 10,11                    | Physical Device   |
| Performance Testing | 12,15            | 8.0,11                   | Mid/High-End Device |

Automated Testing Configuration

// detox.config.js - Cross-Platform Testing Configuration
module.exports = {
  configurations: {
    'ios.sim.debug': {
      device: 'iPhone 13',
      os: 'ios',
      build: 'xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator',
      binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/MyApp.app'
    },
    'android.emu.debug': {
      device: 'Pixel_4_API_30',
      os: 'android',
      build: 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
      binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk'
    }
  }
};

Cross-Platform Performance Optimization

Platform-Specific Optimization Strategies

// Performance Optimization Example: List Rendering
import { FlatList, Platform } from 'react-native';

const OptimizedList = () => (
  <FlatList
    data={data}
    renderItem={renderItem}
    // iOS-Specific Optimization
    initialNumToRender={Platform.OS === 'ios' ? 10 : 5}
    // Android-Specific Optimization
    windowSize={Platform.OS === 'android' ? 5 : 7}
    // General Optimization
    keyExtractor={(item) => item.id.toString()}
    maxToRenderPerBatch={5}
    updateCellsBatchingPeriod={50}
  />
);

Memory Management Best Practices

// Image Loading Optimization Example
import FastImage from 'react-native-fast-image';

const PlatformOptimizedImage = ({ uri }) => (
  <FastImage
    source={{
      uri,
      priority: Platform.OS === 'ios' ? FastImage.priority.normal : FastImage.priority.high,
      cache: Platform.OS === 'android' 
        ? FastImage.cacheControl.immutable 
        : FastImage.cacheControl.web
    }}
    resizeMode={FastImage.resizeMode.contain}
  />
);

Real-Time Application Development

WebSocket and Real-Time Data Updates

WebSocket Connection Management

// WebSocketService.js
import { useEffect, useState } from 'react';

export const useWebSocket = (url) => {
  const [socket, setSocket] = useState(null);
  const [isConnected, setIsConnected] = useState(false);

  useEffect(() => {
    const ws = new WebSocket(url);
    
    ws.onopen = () => {
      setIsConnected(true);
      console.log('WebSocket connected');
    };
    
    ws.onclose = () => {
      setIsConnected(false);
      console.log('WebSocket disconnected');
      // Auto-Reconnect Logic
      setTimeout(() => setSocket(new WebSocket(url)), 3000);
    };
    
    ws.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
    
    setSocket(ws);

    return () => {
      ws.close();
    };
  }, [url]);

  const sendMessage = (message) => {
    if (socket && isConnected) {
      socket.send(JSON.stringify(message));
    }
  };

  return { sendMessage, isConnected };
};

Real-Time Data Update Component

// RealTimeDataComponent.js
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import { useWebSocket } from './WebSocketService';

const RealTimeDataComponent = () => {
  const [data, setData] = useState(null);
  const { sendMessage, isConnected } = useWebSocket('wss://api.example.com/realtime');

  useEffect(() => {
    // Subscribe to Data Updates
    sendMessage({ type: 'subscribe', channel: 'updates' });
    
    // Simulate Data Reception (Actual Implementation Should Handle WebSocket Events)
    const interval = setInterval(() => {
      setData(prev => ({
        ...prev,
        timestamp: Date.now(),
        value: Math.random()
      }));
    }, 1000);

    return () => clearInterval(interval);
  }, [sendMessage]);

  return (
    <View>
      <Text>Connection Status: {isConnected ? 'Connected' : 'Disconnected'}</Text>
      <Text>Real-Time Data: {JSON.stringify(data)}</Text>
    </View>
  );
};

GraphQL and React Native Integration (Apollo Client)

Apollo Client Configuration

// apolloClient.js
import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';

const httpLink = new HttpLink({
  uri: 'https://api.example.com/graphql',
});

const wsLink = new WebSocketLink({
  uri: 'wss://api.example.com/graphql',
  options: {
    reconnect: true,
    connectionParams: {
      authToken: 'YOUR_AUTH_TOKEN',
    },
  },
});

const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink,
);

export const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});

Subscribing to Real-Time Data

// RealTimeGraphQLComponent.js
import React from 'react';
import { useSubscription } from '@apollo/client';
import { NEW_MESSAGE_SUBSCRIPTION } from './graphql/subscriptions';

const RealTimeGraphQLComponent = () => {
  const { data, loading } = useSubscription(NEW_MESSAGE_SUBSCRIPTION);

  if (loading) return <Text>Loading...</Text>;

  return (
    <Text>Latest Message: {data.newMessage.content}</Text>
  );
};

Real-Time Collaborative Editing Implementation (CRDT, OT Algorithms)

CRDT Data Structure Example

// crdtText.js - Simple CRDT Text Implementation
class CRDTText {
  constructor() {
    this.characters = []; // Store Characters and Metadata
    this.siteId = Math.random().toString(36).substr(2, 9); // Unique Site ID
    this.counter = 0; // Incrementing Counter
  }

  // Local Character Insertion
  insert(position, char) {
    const newChar = {
      value: char,
      siteId: this.siteId,
      counter: this.counter++,
      position: position,
    };
    this.characters.splice(position, 0, newChar);
    return newChar;
  }

  // Local Character Deletion
  delete(position) {
    return this.characters.splice(position, 1)[0];
  }

  // Get Current Text
  getText() {
    return this.characters.map(c => c.value).join('');
  }

  // Handle Remote Operations (Simplified Version)
  applyRemoteOperation(operation) {
    if (operation.type === 'insert') {
      // Check for Conflicts and Handle
      this.characters.splice(operation.position, 0, operation.char);
    } else if (operation.type === 'delete') {
      this.characters.splice(operation.position, 1);
    }
  }
}

Integration into React Component

// CollaborativeEditor.js
import React, { useState, useEffect } from 'react';
import { TextInput, View } from 'react-native';
import { CRDTText } from './crdtText';
import { useWebSocket } from './WebSocketService';

const CollaborativeEditor = () => {
  const [text, setText] = useState('');
  const [localCRDT, setLocalCRDT] = useState(new CRDTText());
  const { sendMessage } = useWebSocket('wss://api.example.com/collab');

  const handleTextChange = (newText) => {
    // Calculate Differences and Generate Operations
    const operations = calculateDiff(text, newText, localCRDT);
    
    // Apply Local Operations
    operations.forEach(op => {
      if (op.type === 'insert') {
        localCRDT.insert(op.position, op.char);
      } else if (op.type === 'delete') {
        localCRDT.delete(op.position);
      }
    });
    
    // Update Local State
    setText(localCRDT.getText());
    
    // Send Operations to Server
    operations.forEach(op => {
      sendMessage({
        type: 'text_operation',
        operation: op,
        siteId: localCRDT.siteId,
      });
    });
  };

  // Receive Remote Operations (via WebSocket)
  useEffect(() => {
    // WebSocket Message Handling Logic...
  }, []);

  return (
    <View>
      <TextInput
        value={text}
        onChangeText={handleTextChange}
        multiline
      />
    </View>
  );
};

Performance Optimization for Real-Time Applications

Message Batching and Throttling

// messageBatcher.js
export class MessageBatcher {
  constructor(sendFn, delay = 100) {
    this.sendFn = sendFn;
    this.delay = delay;
    this.batch = [];
    this.timer = null;
  }

  add(message) {
    this.batch.push(message);
    
    if (!this.timer) {
      this.timer = setTimeout(() => {
        this.flush();
      }, this.delay);
    }
  }

  flush() {
    if (this.batch.length > 0) {
      this.sendFn(this.batch);
      this.batch = [];
    }
    this.timer = null;
  }
}

// Usage Example
const batcher = new MessageBatcher((messages) => {
  websocket.send(JSON.stringify(messages));
});

// In Event Handler
textInput.onChangeText((text) => {
  batcher.add({
    type: 'text_update',
    content: text,
    timestamp: Date.now()
  });
});

Data Compression and Binary Protocol

// binaryProtocol.js
export const encodeMessage = (message) => {
  // Simple Example: Convert JSON to Binary Format
  const jsonStr = JSON.stringify(message);
  const encoder = new TextEncoder();
  return encoder.encode(jsonStr);
};

export const decodeMessage = (binaryData) => {
  const decoder = new TextDecoder();
  const jsonStr = decoder.decode(binaryData);
  return JSON.parse(jsonStr);
};

// WebSocket Usage Example
websocket.binaryType = 'arraybuffer';
websocket.onmessage = (event) => {
  if (event.data instanceof ArrayBuffer) {
    const message = decodeMessage(event.data);
    handleMessage(message);
  } else {
    // Handle Text Messages
  }
};

Security and Permission Control in Real-Time Applications

JWT Authentication Integration

// authContext.js
import React, { createContext, useContext, useState, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [token, setToken] = useState(null);

  useEffect(() => {
    // Load Token from Storage
    AsyncStorage.getItem('jwt_token').then(storedToken => {
      if (storedToken) setToken(storedToken);
    });
  }, []);

  const login = async (newToken) => {
    setToken(newToken);
    await AsyncStorage.setItem('jwt_token', newToken);
  };

  const logout = async () => {
    setToken(null);
    await AsyncStorage.removeItem('jwt_token');
  };

  // Inject Token in WebSocket Connection
  const getWebSocketHeaders = () => {
    return token ? { Authorization: `Bearer ${token}` } : {};
  };

  return (
    <AuthContext.Provider value={{ token, login, logout, getWebSocketHeaders }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => useContext(AuthContext);

Secure WebSocket Connection

// secureWebSocket.js
import { useAuth } from './authContext';

export const useSecureWebSocket = (url) => {
  const { getWebSocketHeaders } = useAuth();
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const ws = new WebSocket(url);
    
    // Set Authentication Headers (Actual Implementation May Use Cookies or Other Mechanisms)
    ws.onopen = () => {
      if (getWebSocketHeaders().Authorization) {
        // Some WebSocket Implementations May Require Sending Authentication Message
        ws.send(JSON.stringify({
          type: 'authentication',
          token: getWebSocketHeaders().Authorization.split(' ')[1]
        }));
      }
    };
    
    setSocket(ws);
    
    return () => ws.close();
  }, [url, getWebSocketHeaders]);

  return socket;
};

Enterprise-Level Application Development

Complex State Management (Redux Saga, Redux Observable)

Redux Saga for Complex Workflows

// sagas/authSaga.js
import { call, put, takeLatest } from 'redux-saga/effects';
import api from '../api';
import { loginSuccess, loginFailure } from '../actions/auth';

function* loginSaga(action) {
  try {
    const { username, password } = action.payload;
    const response = yield call(api.login, username, password);
    yield put(loginSuccess(response.data.token));
    
    // Optional: Perform Follow-Up Actions
    yield call(storeToken, response.data.token);
    yield call(navigateToHome);
  } catch (error) {
    yield put(loginFailure(error.message));
  }
}

export default function* authSaga() {
  yield takeLatest('LOGIN_REQUEST', loginSaga);
}

// sagas/watchAllSagas.js
import { all } from 'redux-saga/effects';
import authSaga from './authSaga';
import dataSaga from './dataSaga';

export default function* rootSaga() {
  yield all([
    authSaga(),
    dataSaga(),
    // Other Sagas...
  ]);
}

Redux Observable for Reactive Streams

// epics/dataEpic.js
import { ofType } from 'redux-observable';
import { mergeMap, map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import api from '../api';
import { fetchDataSuccess, fetchDataFailure } from '../actions/data';

const fetchDataEpic = (action$) =>
  action$.pipe(
    ofType('FETCH_DATA_REQUEST'),
    mergeMap((action) =>
      api.fetchData(action.payload).pipe(
        map((response) => fetchDataSuccess(response.data)),
        catchError((error) => of(fetchDataFailure(error.message)))
      )
    )
  );

export default fetchDataEpic;

Data Synchronization and Conflict Resolution

Optimistic Update Strategy

// optimisiticUpdate.js
export const updateTodoOptimistically = (store, todoId, changes) => {
  // 1. Immediately Update Local State
  store.dispatch({
    type: 'TODO_UPDATE_OPTIMISTIC',
    payload: { id: todoId, changes },
  });
  
  // 2. Send Request to Server
  api.updateTodo(todoId, changes).catch((error) => {
    // 3. Rollback Changes if Failed
    store.dispatch({
      type: 'TODO_UPDATE_ROLLBACK',
      payload: { id: todoId, originalData: error.originalData },
    });
  });
};

// Reducer Handling
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case 'TODO_UPDATE_OPTIMISTIC':
      return state.map(todo =>
        todo.id === action.payload.id
          ? { ...todo, ...action.payload.changes }
          : todo
      );
    case 'TODO_UPDATE_ROLLBACK':
      return state.map(todo =>
        todo.id === action.payload.id
          ? action.payload.originalData
          : todo
      );
    default:
      return state;
  }
};

Server-Side Conflict Resolution

// Conflict Resolution Strategy Example
const resolveConflict = (localData, serverData) => {
  // Simple Timestamp-Based Conflict Resolution
  if (new Date(localData.updatedAt) > new Date(serverData.updatedAt)) {
    return { ...serverData, ...localData, updatedAt: new Date() };
  } else {
    return serverData;
  }
};

// Use in Data Synchronization
api.syncData(localData).then(response => {
  if (response.conflict) {
    const resolvedData = resolveConflict(localData, response.serverData);
    dispatch(updateData(resolvedData));
  } else {
    dispatch(updateData(response.data));
  }
});

Offline Support and Data Persistence

Redux Persist Configuration

// store.js
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import rootReducer from './reducers';

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  whitelist: ['auth', 'userPreferences'], // Persist Only These Reducers
  blacklist: ['temporaryData'], // Do Not Persist These Reducers
  transforms: [
    // Optional: Custom Transformers for Specific Data
  ],
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore(persistedReducer);
export const persistor = persistStore(store);

// App.js
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store';

const App = () => (
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <MainApp />
    </PersistGate>
  </Provider>
);

Local Database Integration (Realm)

// realmService.js
import Realm from 'realm';

// Define Schema
const TodoSchema = {
  name: 'Todo',
  primaryKey: 'id',
  properties: {
    id: 'string',
    text: 'string',
    completed: { type: 'bool', default: false },
    updatedAt: 'date',
  },
};

// Initialize Realm
let realmInstance = null;

export const initRealm = async () => {
  realmInstance = await Realm.open({
    schema: [TodoSchema],
  });
  return realmInstance;
};

// CRUD Operations
export const addTodo = (todo) => {
  return realmInstance.write(() => {
    realmInstance.create('Todo', {
      ...todo,
      id: generateId(),
      updatedAt: new Date(),
    });
  });
};

export const getTodos = () => {
  return realmInstance.objects('Todo').filtered('completed = false');
};

Security and Permission Control (JWT, OAuth)

Secure Storage Implementation

// secureStorage.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Keychain from 'react-native-keychain';

export const secureStoreData = async (key, value) => {
  try {
    // Sensitive Data Uses Keychain
    if (key === 'auth_token' || key === 'refresh_token') {
      await Keychain.setGenericPassword(key, value);
    } else {
      // Non-Sensitive Data Uses AsyncStorage
      await AsyncStorage.setItem(key, value);
    }
  } catch (error) {
    console.error('Secure storage error:', error);
  }
};

export const secureGetData = async (key) => {
  try {
    if (key === 'auth_token' || key === 'refresh_token') {
      const credentials = await Keychain.getGenericPassword();
      if (credentials && credentials.username === key) {
        return credentials.password;
      }
    } else {
      return await AsyncStorage.getItem(key);
    }
  } catch (error) {
    console.error('Secure get error:', error);
    return null;
  }
};

OAuth2.0 Integration

// oauthService.js
import { SecureStore } from 'expo-secure-store';
import axios from 'axios';

const OAUTH_CONFIG = {
  clientId: 'your_client_id',
  redirectUri: 'your_app_scheme://oauth/callback',
  scopes: ['openid', 'profile', 'email'],
};

export const startOAuthFlow = () => {
  const authUrl = `https://auth.example.com/oauth/authorize?client_id=${OAUTH_CONFIG.clientId}&redirect_uri=${encodeURIComponent(OAUTH_CONFIG.redirectUri)}&scope=${OAUTH_CONFIG.scopes.join(' ')}`;
  
  // Open Browser for Authentication in React Native
  Linking.openURL(authUrl);
};

// Handle Callback URL
export const handleOAuthCallback = async (url) => {
  if (!url.startsWith(OAUTH_CONFIG.redirectUri)) return null;
  
  const code = new URL(url).searchParams.get('code');
  if (!code) return null;
  
  // Exchange Code for Token
  const tokenResponse = await axios.post('https://auth.example.com/oauth/token', {
    grant_type: 'authorization_code',
    code,
    redirect_uri: OAUTH_CONFIG.redirectUri,
    client_id: OAUTH_CONFIG.clientId,
  });
  
  // Securely Store Tokens
  await SecureStore.setItemAsync('access_token', tokenResponse.data.access_token);
  await SecureStore.setItemAsync('refresh_token', tokenResponse.data.refresh_token);
  
  return tokenResponse.data;
};

Enterprise-Level Application Architecture Design

Layered Architecture Example

src/
├── api/                  # API Service Layer
│   ├── authService.js    # Authentication-Related APIs
│   ├── dataService.js    # Data Operation APIs
│   └── apiClient.js      # Base Request Configuration
├── features/             # Feature Modules
│   ├── auth/             # Authentication Module
│   │   ├── components/   # Module Components
│   │   ├── hooks/        # Module Hooks
│   │   ├── slices/       # Redux Slices
│   │   └── screens/      # Module Screens
│   └── projects/         # Projects Module
├── lib/                  # Shared Libraries
│   ├── persistence/      # Data Persistence
│   ├── utils/            # Utility Functions
│   └── constants/        # Global Constants
├── navigation/           # Routing Configuration
├── store/                # State Management
│   ├── rootReducer.js    # Root Reducer
│   ├── rootSaga.js       # Root Saga
│   └── store.js          # Store Configuration
├── App.js                # Application Entry
└── index.js              # Render Entry

Micro-Frontend Integration Solution

// Main Application Configuration (Using Module Federation)
// webpack.config.js (Main Application)
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;

module.exports = {
  // ...other configurations
  plugins: [
    new ModuleFederationPlugin({
      name: 'main_app',
      remotes: {
        analytics_module: 'analytics_module@http://localhost:3001/remoteEntry.js',
      },
      shared: {
        react: { singleton: true },
        'react-native': { singleton: true },
      },
    }),
  ],
};

// Submodule Configuration
// webpack.config.js (Submodule)
new ModuleFederationPlugin({
  name: 'analytics_module',
  filename: 'remoteEntry.js',
  exposes: {
    './Analytics': './src/Analytics',
  },
  shared: {
    react: { singleton: true },
    'react-native': { singleton: true },
  },
});

// Dynamically Load Submodule
import React, { Suspense } from 'react';

const Analytics = React.lazy(() => import('analytics_module/Analytics'));

const App = () => (
  <Suspense fallback={<ActivityIndicator />}>
    <Analytics />
  </Suspense>
);

Plugin-Based Architecture Design

// Plugin System Implementation
// PluginManager.js
export class PluginManager {
  constructor() {
    this.plugins = new Map();
  }

  registerPlugin(pluginName, plugin) {
    if (this.plugins.has(pluginName)) {
      console.warn(`Plugin ${pluginName} already registered`);
      return;
    }
    this.plugins.set(pluginName, plugin);
  }

  unregisterPlugin(pluginName) {
    this.plugins.delete(pluginName);
  }

  executeHook(hookName, ...args) {
    for (const plugin of this.plugins.values()) {
      if (typeof plugin[hookName] === 'function') {
        plugin[hookName](...args);
      }
    }
  }

  getPlugin(pluginName) {
    return this.plugins.get(pluginName);
  }
}

// Usage Example
const pluginManager = new PluginManager();

// Register Plugin
pluginManager.registerPlugin('analytics', {
  onUserLogin: (user) => {
    console.log('Analytics: User logged in', user);
    // Send Analytics Event
  },
});

// Trigger Hook
pluginManager.executeHook('onUserLogin', currentUser);
Share your love