Skip to content
All question banks

Mobile Development

React Native Questions

Comprehensive guide covering React Native fundamentals, Architecture, Styling, and Component Communication. Each answer is technically rigorous for professional interviews.

250 of 250 questions

React Native Basics24

React Native is an open-source framework developed by Meta that allows developers to build natively-rendered mobile applications for iOS and Android using JavaScript and React. It enables code sharing across platforms while maintaining access to native platform capabilities through a bridge or direct interface.

While both use the same component logic and lifecycle, React targets the browser DOM using HTML elements like <div> and <span>, whereas React Native targets mobile platforms using native components like <View> and <Text> that map directly to their respective iOS (UIView) and Android (View) counterparts.

Key features include 'Hot Reloading' and 'Fast Refresh' for near-instant code updates, a massive ecosystem of libraries, the ability to write native code in Java/Swift when needed, and a unified development experience that allows a single codebase to run on both iOS and Android.

JSX stands for JavaScript XML. It is a syntax extension for JavaScript that allows you to write HTML-like structures directly within your JS files. React Native uses JSX to define the UI hierarchy, which is later compiled into standard JavaScript calls that create native component instances.

Components are the building blocks of a React Native application. They are independent, reusable pieces of UI logic that can be combined to form a complex interface. Components manage their own state and receive data via props, following a declarative programming model where the UI reflects the current state.

Functional components are simple JavaScript functions that return JSX and use 'Hooks' for state management. Class components are ES6 classes that extend React.Component and use 'this.state' and lifecycle methods. Functional components are now the standard due to better readability and performance optimizations like Hooks.

You can create a project using the command 'npx react-native init ProjectName' for a CLI-based workflow or 'npx create-expo-app ProjectName' for an Expo-managed workflow. The CLI approach provides more control over native modules, while Expo simplifies the initial setup and development process.

AppRegistry is the JavaScript entry point to run all React Native apps. It is used to register the root component of your application so that the native OS (iOS/Android) knows which component to load and render when the application is launched from the home screen.

React Native provides essential core components like <View> for layout, <Text> for displaying strings, <Image> for graphics, <ScrollView> for scrollable containers, and <TextInput> for user input. These are platform-agnostic wrappers that render as native UI elements on each platform.

The <View> component is the fundamental building block for UI in React Native. It is a container that supports layout with Flexbox, styling, and touch handling. It maps to 'UIView' on iOS and 'android.view' on Android, acting similarly to a <div> in web development.

The <Text> component is used for displaying text in React Native. Unlike the web, where text can live inside many elements, in React Native, all text must be wrapped in a <Text> component. It supports nested styling and handles various font properties and text-wrapping behaviors across platforms.

TouchableOpacity is a wrapper used to make views respond properly to touches. When pressed, the opacity of the wrapped view is decreased, providing visual feedback to the user. It is the primary way to create buttons or interactive elements that feel native and responsive.

SafeAreaView is a component used to render content within the safe area boundaries of a device. It automatically applies padding to reflect the physical limitations of the screen, such as rounded corners, camera notches, or the home indicator on devices like the iPhone X and later.

Images are used via the <Image> component. You can display local images using the 'require' syntax (source={require('./path/to/img.png')}) or network images using an object with a 'uri' key (source={{uri: 'https://link.com/img.png'}}). Network images require explicit width and height styling.

No. While the logic (Hooks, State, Props) is the same, components that use web-specific APIs like <div>, <ul>, or window.document are not usable. You must use React Native specific components that map to mobile native views to ensure the code can run on iOS and Android.

React Native CLI offers full access to the native Android and iOS folders, allowing for custom native modules and complex configurations. Expo is a managed workflow that hides native complexity, providing a faster setup and easy Over-the-Air updates, but it limits access to custom native code.

Advantages include 'Learn Once, Write Anywhere,' which saves development time; high performance through native rendering; a strong community; and features like 'Fast Refresh.' It also allows developers to push updates directly to users via CodePush without waiting for app store approval.

Limitations include performance overhead for very complex animations, the occasional need for platform-specific native code (Java/Swift), larger app sizes compared to purely native apps, and the delay in supporting the latest native platform features immediately upon their release.

The JavaScript code is bundled and executed by a JS engine (like Hermes). It communicates UI updates to the 'Shadow Thread,' which calculates the layout using the Yoga engine. These layout instructions are then passed to the 'Main Thread' to render the actual native views on the screen.

The bridge is the legacy asynchronous communication layer between the JavaScript thread and the Native thread. It uses JSON serialization to pass messages back and forth. While effective, it can become a bottleneck when passing large amounts of data or handling high-frequency events like fast scrolling.

In the legacy architecture, it uses the 'Bridge' to send serialized JSON messages. In the 'New Architecture,' it uses the JavaScript Interface (JSI), which allows the JS thread to hold references to C++ host objects and call methods on them directly and synchronously, significantly improving performance.

Native modules are pieces of Java, Kotlin, Objective-C, or Swift code that expose native platform APIs (like Camera, GPS, or Fingerprint sensor) to JavaScript. They are used when a required feature isn't available in the core React Native library or requires high-performance native execution.

The Shadow Thread is where React Native calculates the layout of your components. It uses the 'Yoga' layout engine to convert Flexbox styles into specific coordinates (top, left, width, height) which are then sent to the Main (UI) thread to actually place the native views on the screen.

Pressable is a newer, more flexible core component for handling touch interactions. Unlike TouchableOpacity, it provides 'PressableState' (pressed, hovered, focused) which allows for more complex styling logic and better accessibility control without the fixed 'opacity' effect.

Props, State & Component Communication11

Props (short for properties) are read-only data passed from a parent component to a child component. They allow components to be dynamic and reusable by customizing their behavior and appearance. Props flow in a single direction (downward) in the component tree.

State is an internal data store that allows a component to track and respond to changes over time. Lifecycle methods (in class components) or Hooks (in functional components) are triggers that run at specific stages of a component's life, such as mounting, updating, or unmounting.

Props are external parameters passed to a component and are immutable from the component's perspective. State is internal data managed within the component itself and is mutable via 'setState' or 'useState.' Changing state triggers a re-render of the component to update the UI.

Props drilling occurs when data needs to be passed from a high-level parent component to a deeply nested child component, requiring the data to be passed as props through intermediate components that do not actually use the data themselves, leading to cluttered and unmaintainable code.

Props drilling can be avoided using the 'Context API' for global data sharing, or state management libraries like 'Redux' or 'Zustand.' Another approach is 'Component Composition,' where components are passed as props, allowing the parent to define the structure more directly.

Lifting state up is a pattern where the state is moved from multiple child components to their closest common ancestor. This allows the parent to manage the state and pass it back down as props, ensuring all children stay synchronized when the data changes.

The 'key' prop is a unique identifier used by React to track which items in a list have changed, been added, or been removed. It helps the reconciliation algorithm efficiently update the UI by minimizing re-renders and ensuring that component state is preserved correctly in dynamic lists.

A controlled component has its value managed by the component's state (via value and onChangeText props). In an uncontrolled component, the source of truth is the native DOM/View itself, and values are accessed using 'refs' only when needed, rather than tracking every keystroke in state.

User input is handled primarily using the <TextInput> component. It provides props like 'onChangeText' to update state with the new string, 'onSubmitEditing' for enter key actions, and 'keyboardType' to show specific keyboards (numeric, email) based on the input requirement.

A <Modal> is a core component that covers the entire screen or a significant portion to display critical content. A 'popup' is usually a temporary UI element like an 'Alert' or a custom 'Tooltip' that is smaller and less intrusive than a full-screen modal transition.

Render props is a pattern where a component's prop is a function that returns a React element. This allows for logic sharing between components by letting the parent decide how the child's data should be rendered, providing high flexibility in UI customization.

Styling & Layout10

Styling is done using the 'style' prop and standard JavaScript objects. While the names are similar to CSS (e.g., backgroundColor, padding), React Native uses CamelCase and does not support all CSS properties. Most layouts are achieved using the 'Flexbox' system provided by the Yoga engine.

StyleSheet is an abstraction similar to CSS stylesheets. Using 'StyleSheet.create' allows you to define styles once, which are then sent across the bridge as IDs rather than objects. This improves performance and keeps the code organized by separating styles from component logic.

Flexbox is a layout model designed to provide a consistent layout on different screen sizes. In React Native, 'flexDirection' defaults to 'column' (unlike the web's 'row'), and components use 'flex', 'justifyContent', and 'alignItems' to distribute space and align content within a container.

React Native handles screen sizes primarily using Flexbox for liquid layouts. Developers also use the 'Dimensions' API to get screen width/height for manual calculations and the 'PixelRatio' API to handle different display densities, ensuring the UI looks consistent on all devices.

Fixed width/height values are density-independent pixels (dp), which scale according to the device's screen density. Percentage values (e.g., width: '50%') are relative to the parent container's size. Percentages are useful for responsive grids, while pixels are better for fixed-size icons.

Theming is typically implemented using the 'Context API' to provide a theme object (colors, spacing) to the entire app. Components consume this context to apply styles. Popular libraries like 'styled-components' or 'react-native-paper' offer built-in theming providers and hooks like 'useTheme'.

React Native uses 'dp' (Density-independent Pixels) on Android and 'pt' (Points) on iOS. These are not physical pixels but units that scale based on the device's screen density. 1 unit in React Native looks roughly the same physical size on a low-res screen as it does on a high-res 'Retina' screen.

This hook provides the current screen dimensions and automatically updates when the screen rotates. It is preferred over the 'Dimensions' API because it follows the React lifecycle, ensuring your responsive styles re-render correctly when the device orientation changes.

Sticky headers are section headers that stay at the top of the view while scrolling. They are enabled in FlatList or ScrollView by providing an array of item indices to the 'stickyHeaderIndices' prop, or automatically when using a SectionList for grouped data.

Effective dark mode uses the 'useColorScheme' hook to detect the system theme. You define a 'theme' object for both modes and use the 'useTheme' hook (if using a library like Paper) to apply the correct colors. This ensures the app transitions seamlessly when the system theme changes.

Hooks15

Hooks are functions that allow functional components to 'hook into' React features. Common hooks include 'useState' for local state, 'useEffect' for side effects, 'useContext' for accessing the Context API, and 'useRef' for accessing native DOM-like references or persistent values.

useState is used by calling it with an initial value: 'const [state, setState] = useState(initialValue);'. It returns the current state value and a function to update it. When 'setState' is called, React triggers a re-render of the component with the updated value.

useEffect is used to perform side effects in functional components, such as API calls, subscriptions, or manual DOM/native changes. It runs after every render by default but can be configured to run only when specific dependencies change by passing a dependency array.

'componentDidMount' only runs once after the component is mounted in class components. 'useEffect' with an empty dependency array ([]) mimics this behavior, but without the array, it runs after every render, making it more flexible for combined lifecycle management.

useCallback memoizes a function to prevent its re-creation on every render, which is useful when passing functions to optimized child components. useMemo memoizes the result of a calculation, avoiding expensive re-computations unless its specific dependencies change, thereby enhancing performance.

useReducer is a hook for managing complex state logic that involves multiple sub-values or when the next state depends on the previous one. It uses a 'reducer' function (similar to Redux) and a 'dispatch' method, providing more structure and predictability than basic useState.

useContext allows a component to subscribe to React Context without nesting multiple consumers. It accepts a context object and returns the current value for that context, enabling easy access to global state like user authentication, language, or themes throughout the app tree.

useRef returns a mutable ref object whose '.current' property persists throughout the component's lifecycle. It is used to directly access native views (e.g., to focus a TextInput) or to store any mutable value that shouldn't trigger a re-render when it changes.

The dependency array is the second argument to useEffect. It tells React which values the effect relies on. If any value in the array changes between renders, the effect re-runs. If the array is empty, the effect runs only once after the initial mount.

Cleanup is handled by returning a function from the useEffect. This cleanup function runs before the component unmounts and before the effect re-runs (if it has dependencies). It is essential for removing timers, canceling network requests, or unsubscribing from events to prevent memory leaks.

Hooks must only be called at the 'Top Level'—never inside loops, conditions, or nested functions. They must also only be called from 'React Functions' (components or custom hooks). These rules ensure that React can maintain the correct order of hooks across multiple renders.

useReducer is an alternative to useState used for managing complex state objects where the next state depends on the previous one. It takes a reducer function and an initial state, returning the current state and a 'dispatch' function to trigger transitions, providing a mini-Redux-like pattern within a component.

useImperativeHandle allows a child component to customize the instance value that is exposed to its parent when using 'ref'. It is typically used with 'forwardRef' to hide internal implementation details while only exposing specific methods (like .focus() or .scrollTo()) to the parent.

A custom hook is a standard JavaScript function that starts with the word 'use' and can call other hooks internally. They are used to extract and share stateful logic between components, such as 'useAuth' for session management or 'useNetwork' for tracking connectivity status.

useMemo caches the 'result' of an expensive calculation (like sorting a list), while useCallback caches the 'function definition' itself. Both are used to prevent unnecessary re-renders in children that rely on referential equality to determine if they should update.

Lists & Performance14

FlatList is a high-performance component used for rendering large, scrollable lists of data. Unlike a basic ScrollView, FlatList only renders the items currently visible on the screen (windowing), which significantly reduces memory consumption and improves scroll performance for long lists.

ScrollView renders all child components at once upon mounting, which is memory-intensive for large datasets. FlatList uses 'virtualization' to only render items currently visible on the screen, recycling views to maintain a low memory footprint and ensuring smooth 60fps scrolling even with thousands of items.

SectionList is used when your data needs to be grouped into subcategories with sticky headers, such as an alphabetized contact list or a grouped settings menu. It offers the same virtualization benefits as FlatList but adds built-in support for section headers and separators.

getItemLayout is an optimization prop that allows you to skip the measurement of dynamic content if you know the height (or width) of your items in advance. By providing this, FlatList can immediately calculate the scroll position, significantly boosting performance by avoiding expensive layout calculations during scrolling.

To optimize images, you should use 'react-native-fast-image' for better caching and aggressive disk/memory management. Additionally, always resize images to the actual display size before loading and use the 'WebP' format to reduce payload size and memory consumption on the bridge.

InteractionManager allows you to schedule long-running tasks (like data processing or heavy API calls) to run after any active animations or interactions have finished. This prevents the UI thread from dropping frames, ensuring that navigations and touch responses feel smooth and uninterrupted.

Memory leaks are prevented by always cleaning up side effects in the 'useEffect' return function, such as clearing timeouts, intervals, and removing event listeners. You should also ensure that no stale closures are holding references to large objects or UI elements after a component unmounts.

The key prop acts as a unique stable identifier that helps React's reconciliation algorithm determine which items in a list have been changed, added, or removed. Using an index as a key is discouraged as it can lead to UI bugs and performance issues when the list order is dynamic.

Optimization includes enabling Hermes, reducing the number of synchronized native modules initialized at startup, using 'Lazy Loading' for heavy components, and minimizing the size of the initial JS bundle by removing unused libraries and assets.

Standard <Image /> has basic caching, but for production, 'react-native-fast-image' is the standard. It uses Glide (Android) and SDWebImage (iOS) to handle aggressive disk and memory caching, placeholder support, and priority loading, ensuring images appear instantly on return visits.

ViewabilityConfig allows you to define when an item is considered 'visible' (e.g., 50% of the item is on screen for 500ms). This is used to trigger analytics events (impressions), auto-play videos when they come into view, or lazy-load high-resolution data for specific list items.

Optimization for low-end devices involves using Hermes, reducing the JS bundle size, using 'FlatList' with small 'windowSize' props, avoiding complex shadow styles (which are expensive to render on Android), and minimizing the number of bridge crossings for UI updates.

Infinite scrolling is implemented using FlatList's 'onEndReached' prop. When the user scrolls near the bottom (controlled by 'onEndReachedThreshold'), a function is triggered to fetch the next page of data and append it to the current list state.

FlashList is a high-performance replacement for FlatList. It uses a 'recycling' technique that is significantly faster than standard virtualization. It prevents 'blank spaces' when scrolling quickly and uses much less CPU, making it the current industry standard for very large, high-speed lists.

Navigation4

Navigation is primarily implemented using the 'React Navigation' library. It provides a declarative API to define the app's structure through various 'Navigators' (Stack, Tab, Drawer). These navigators are wrapped in a 'NavigationContainer' which maintains the navigation state across the entire application tree.

Stack Navigator provides a way to transition between screens where each new screen is placed on top of a stack, mimicking standard 'push' and 'pop' mobile behavior. Tab Navigator allows users to switch between different routes at the bottom (or top) of the screen, representing parallel views that persist their state.

Parameters are passed by providing an object as the second argument to the 'navigate' function: navigation.navigate('Profile', { userId: '123' }). On the receiving screen, these parameters are accessed via the 'route.params' object, allowing the component to render data based on the passed ID.

Common bottlenecks include rendering heavy components within the screen options, using a large number of nested navigators, and failing to use 'react-native-screens' which optimizes memory by only keeping the current and transition screens in the native view hierarchy.

State Management6

Redux is a predictable state container used to manage complex global state across an entire application. It centralizes data into a single 'Store' and uses 'Actions' and 'Reducers' to update that state, making data flow transparent and debugging easier through specialized tools like Redux DevTools.

Use Context API for simpler state needs like the current user, theme, or language settings that don't change frequently. Redux is better suited for large-scale applications with complex logic, frequent state updates, and a need for middleware (like logging or persistent storage) or advanced performance optimization.

Middleware like Thunk or Saga is used to handle 'side effects' such as API calls or asynchronous logic. Redux Thunk allows actions to return functions (instead of plain objects), while Redux Saga uses generator functions to handle more complex, multi-step asynchronous workflows in a highly testable way.

Zustand is a modern, lightweight state management library that offers a simpler API than Redux without the boilerplate. It uses hooks for selective re-rendering, meaning components only update when the specific piece of state they subscribe to changes, providing excellent performance with minimal setup.

React Query is designed specifically for managing 'server state.' It automates data fetching, caching, synchronization, and error handling. It replaces much of the boilerplate found in Redux for API calls by providing built-in status management (loading/error) and intelligent cache invalidation strategies.

Reselect is used to create 'memoized selectors'. It ensures that complex calculations on the state are only re-run if the specific input state changes. This prevents unnecessary re-renders in components and improves performance in apps with very large global state trees.

Advanced Components & Patterns16

React.memo is a higher-order component that prevents a component from re-rendering if its props haven't changed. It performs a 'shallow comparison' of props, which is a key performance optimization for large lists or deeply nested UI trees where parent updates might trigger unnecessary child renders.

Gestures are handled using the 'react-native-gesture-handler' library, which provides a declarative way to handle complex touch interactions like pan, pinch, and swipe. It runs on the native thread, avoiding the bridge bottleneck and providing a much smoother user experience than the built-in Responder system.

PureComponent is a class-based component that implements a shallow prop and state comparison in 'shouldComponentUpdate'. React.memo is a Higher-Order Component for functional components that does the same for props. Both prevent unnecessary re-renders when data hasn't changed.

An HOC is a function that takes a component and returns a new component with added functionality. Common examples include 'withNavigation' or 'connect' from Redux. While Hooks have replaced many HOC use cases, they remain useful for cross-cutting concerns like logging or access control.

Render props is a technique for sharing code between components using a prop whose value is a function. The component calls this function to determine what to render, allowing it to share its internal state or logic with the consumer without enforcing a specific UI structure.

Compound components are a group of components that work together to manage a shared state implicitly (e.g., a <Select> and its <Option> children). This is usually implemented using the Context API, providing a highly declarative and flexible API for the end developer.

forwardRef is a function that allows a component to pass a 'ref' it receives down to one of its children. This is essential when you build a custom input component and want the parent to be able to call '.focus()' on the internal native TextInput directly.

Conditional rendering is handled using JavaScript logic like 'if' statements, the ternary operator (condition ? <A/> : <B/>), or the logical AND operator (condition && <A/>). Unlike web, you must ensure you don't return plain strings; if a condition is false, return 'null'.

This library allows you to use popular icon sets (FontAwesome, MaterialIcons) as customizable components. It is more efficient than using PNGs because icons are rendered as fonts/vectors, meaning they stay sharp at any size and can be easily colored via props.

setNativeProps is a way to directly modify a native component's properties without triggering a React re-render. It is a 'last resort' escape hatch used for performance-critical updates, such as frequent position updates during a complex gesture or animation.

This method allows a component to opt-out of the rendering process if its state or props haven't changed in a way that affects the UI. It returns a boolean. By returning 'false', you can prevent an expensive re-render and optimize app performance.

React Native implements standard timers like 'setTimeout' and 'setInterval'. However, because JS runs on a single thread, timers might be delayed if the bridge is busy. It is critical to clear these timers in the cleanup phase of a component to avoid leaks.

'setTimeout' schedules a task to run after a minimum delay. 'setImmediate' is designed to execute a script once the current poll phase completes, effectively running it as soon as possible after the current execution block without a specific delay.

Touch events are handled via the Responder System or the 'Gesture Handler' library. Components like 'Pressable' or 'TouchableOpacity' use this system internally. For complex dragging, you use the 'PanResponder' API to track touch movements across the screen.

Zombie timers occur when a 'setInterval' continues running after a component is unmounted. They are handled by storing the timer ID in a 'ref' or variable and calling 'clearInterval' or 'clearTimeout' in the 'useEffect' cleanup function, preventing memory leaks and background processing drain.

Overlapping is handled using the 'KeyboardAvoidingView' component. It automatically adjusts its height or position when the software keyboard appears. For more complex layouts, you can use 'react-native-keyboard-controller' for smoother, native-like interactions between the keyboard and UI elements.

Animations9

The Animated library is the built-in API for creating fluid animations. It allows you to define 'animated values' and map them to component styles. By using 'useNativeDriver: true', you can offload animations to the native UI thread, ensuring they stay at 60fps even if the JS thread is busy.

The Animated library is the core API for building fluid animations. It allows you to create values that can be updated over time and mapped to component style properties. By using the 'native driver', animations can be calculated on the native thread, ensuring they run at 60 FPS even when the JS thread is blocked.

The 'useNativeDriver' prop offloads the animation work from the JavaScript thread to the native UI thread. This is crucial for performance because it avoids the bridge overhead for every frame. However, it only supports non-layout properties like 'opacity' and 'transform' (scale, rotate, translate).

Reanimated is a powerful alternative to the standard Animated API. It allows for complex, gesture-based animations by running all logic on a separate worklet thread. It solves the performance issues of the bridge entirely by allowing synchronous interaction between gestures and the UI.

LayoutAnimation is a global API that automatically animates the next layout change (e.g., adding a new item to a list or resizing a container). It is very performant because it happens entirely on the native side, but it provides less control than the fine-grained Animated API.

Lottie is a library that parses Adobe After Effects animations exported as JSON via Bodymovin and renders them natively on mobile. It allows for high-quality, complex vector animations with very small file sizes compared to GIFs or video files.

The main challenge is the 'bridge' bottleneck. If the animation logic is calculated in JS and sent to native for every frame, the app can stutter if the JS thread is busy with other tasks. This is why libraries like Reanimated and the 'native driver' are essential for high-quality mobile UX.

Custom animations are created by combining Animated.timing, Animated.spring, or Animated.parallel. You define an AnimatedValue, create an animation sequence, and use the '.start()' method to trigger it. These values are then applied to the 'transform' or 'style' props of an Animated.View.

Animated.timing follows a fixed duration and a specific easing curve (like linear or ease-in). Animated.spring uses physics-based models (tension, friction, mass) to create more natural, bouncy movements that mimic real-world objects.

Advanced Topics16

Hermes is a lightweight JavaScript engine optimized for React Native. It reduces app TTI (Time to Interactive) by using pre-compiled bytecode, lowers memory usage, and decreases the final APK/IPA size. It is now the default engine for all new React Native projects to ensure maximum performance.

Large-scale apps use a modular folder structure (feature-based rather than type-based). This involves 'Atomic Design' for components, a 'Services' layer for API calls, and a 'Hooks' layer for business logic. Architectures like 'Clean Architecture' are often applied to ensure the UI is decoupled from the business logic and data sources.

Handling large datasets requires 'normalization' (using tools like Normalizr) to prevent deeply nested objects. For the UI, use 'VirtualizedList' or 'FlashList' to avoid memory bloat. For data fetching, implement 'pagination' or 'infinite scrolling' to ensure only a subset of data is processed by the JS thread at any given time.

A monorepo setup involves placing the React Native app, a shared UI library, and shared utility packages in a single workspace. Tools like 'NX' or 'Turborepo' manage dependencies and shared build caches. This is useful for companies sharing code between a web (React) app and mobile (React Native) apps.

Accessibility ensures users with visual, hearing, or motor impairments can use the app. React Native provides props like 'accessible', 'accessibilityLabel', and 'accessibilityRole'. This allows screen readers (TalkBack on Android, VoiceOver on iOS) to correctly interpret and narrate the UI elements to the user.

Hermes is a JS engine optimized for mobile. It improves startup time by using pre-compiled bytecode. To enable it on Android, set 'enableHermes: true' in 'app/build.gradle'. On iOS, set ':hermes_enabled => true' in the Podfile. It significantly reduces the 'Time to Interactive' metric for large apps.

While code is shared, differences persist in UI defaults (headers, buttons), keyboard behavior, and permissions. Android uses Gradle for builds and 'Activities' for navigation, while iOS uses CocoaPods and 'ViewControllers'. Developers must use the 'Platform' API to apply specific logic or styles for each OS.

A splash screen should be implemented at the native level (LaunchScreen.storyboard for iOS and a custom theme for Android) to show immediately while the JS bundle is loading. Using 'react-native-splash-screen' allows you to programmatically hide the native splash once the React components are ready to render.

react-native-svg allows you to render SVG images as components. You should use it for icons, illustrations, or data visualizations that need to scale infinitely without pixelation. It is much more performant than loading large PNGs for simple shapes and supports dynamic color changes via props.

Backward compatibility is handled through 'feature detection' and conditional checks. For API changes, use 'Version Number' checks. For Native features, use the 'Linking.canOpenURL' or optional chaining for experimental native modules to ensure the app doesn't crash on older OS versions that lack specific APIs.

Common pitfalls include 'dependency bloat' (increasing app size), abandoned libraries that cause build failures on new React Native versions, and 'bridge bottlenecks' where a library passes too much data across the JSON bridge. Always audit a library's maintenance status and bundle impact before integrating.

Data consistency is ensured using a 'Single Source of Truth' pattern. This is implemented via a global state manager (Redux/Zustand) or a caching layer (React Query). When data is updated in the store, all components subscribed to that slice of state re-render automatically, keeping the UI synchronized.

The main trend is the full adoption of the 'New Architecture' (Fabric/TurboModules), leading to more synchronous, high-performance apps. Other trends include the rise of 'Server Components' in mobile, improved monorepo tooling, and tighter integration with AI-driven development tools (Copilot) for scaffolding native modules.

In React Native, code splitting is less about network loading (like Web) and more about 'Bundle Splitting'. You can use dynamic imports or RAM (Random Access Modules) bundles to load only the JS required for the current screen, which improves the initial startup time of very large applications.

Large assets like videos should not be bundled in the app. They should be hosted on a CDN and streamed. For local large files, use 'Git LFS' (Large File Storage) to keep the repository size manageable, and ensure they are optimized/compressed before being added to the native 'assets' folders.

You use the 'AppState' API to detect if the app is 'active', 'background', or 'inactive'. This is useful for pausing timers, closing socket connections, or refreshing data when the user returns to the app from another task or the home screen.

Data Storage & Persistence7

AsyncStorage is an unencrypted, asynchronous, persistent, key-value storage system that is global to the app. It should be used for simple data like user preferences, small JSON objects, or authentication tokens. Because it is unencrypted and has size limits, it should not be used for sensitive information or large datasets.

MMKV is a high-performance key-value storage library written in C++. Unlike AsyncStorage, which communicates over the asynchronous bridge, MMKV uses the JavaScript Interface (JSI) to allow synchronous access to data. This eliminates serialization overhead, making it up to 30x faster for read/write operations.

SQLite is a relational database using SQL queries, ideal for developers comfortable with traditional tables and joins. Realm is an object-oriented database where data is stored as live objects; it is generally faster and requires less boilerplate, but it increases the final application binary size significantly.

Offline storage is implemented by caching API responses in a local database (like WatermelonDB or Realm). When the app is offline, it serves data from the local store. You can use libraries like 'Redux Persist' to save your state tree to disk, ensuring the app state survives an app restart without internet.

WatermelonDB is a high-performance reactive database built on top of SQLite. It is designed for 'offline-first' applications. It only loads data into memory when needed, making it capable of handling tens of thousands of records without slowing down the UI.

To store data safely, you must always wrap calls in try-catch blocks because the disk might be full or the read might fail. Additionally, always stringify objects before saving ('JSON.stringify') and parse them after reading ('JSON.parse') since AsyncStorage only stores strings.

The storage system is crucial for 'session persistence.' It allows users to stay logged in after closing the app and enables features like 'dark mode' settings or 'drafts' to persist locally, reducing the number of unnecessary API calls to the server.

API & Network10

API calls are typically performed using the global 'fetch' API or the 'Axios' library. These requests are asynchronous and return Promises. It is best practice to perform these calls inside a 'useEffect' hook or a dedicated service layer to keep the UI components clean and focused.

Fetch is built into the React Native runtime and is lightweight but requires manual handling of JSON parsing and HTTP errors. Axios is a third-party library that automatically transforms JSON data, supports request/reponse interceptors, and provides better support for tracking upload/download progress.

SSL Pinning ensures the app only communicates with a specific server with a known certificate, preventing Man-in-the-Middle attacks. In React Native, this is usually implemented via native modules like 'react-native-ssl-pinning' or by configuring the native networking stack in iOS (TrustKit) and Android.

Error handling is done using 'try...catch' blocks for async/await or '.catch()' for Promises. You should check the response status code and return user-friendly messages. Global error handling can be managed via Axios interceptors to catch 401 (unauthorized) or 500 (server error) statuses app-wide.

Retry logic automatically attempts a failed network request again after a delay. This is often implemented using libraries like 'axios-retry' or within 'react-query'. It is useful for handling 'flaky' connections where a request might fail temporarily due to poor signal.

API versioning is managed by including the version in the URL (e.g., /v1/users) or in the request headers. In the app, you should maintain a central configuration file for base URLs, allowing you to quickly switch versions or environments (Dev/Prod) without changing every fetch call.

The XHR (XMLHttpRequest) module is the underlying networking layer that React Native uses to implement 'fetch' and 'Axios'. While you rarely use it directly, knowing it exists is helpful for debugging low-level network issues or implementing custom networking logic.

File uploads are handled using the 'FormData' API. You create a new FormData object, append the file (as an object with uri, name, and type), and send it via a POST request. For large files, it is recommended to use 'react-native-fs' to read files from the local storage.

Optimistic UI is a pattern where the app updates the interface immediately after a user action, assuming the API call will succeed. If the call fails, the app reverts the change. This makes the app feel much faster and more responsive to the user.

Performance is managed by using 'caching' (so you don't fetch the same data twice), 'debouncing' (to avoid excessive calls on search inputs), and 'cancellation' (to stop a request if a user navigates away before the data arrives).

Debugging & Testing13

Debugging is done using several tools: the in-app Developer Menu for reloading and toggling 'Show Inspector', Chrome DevTools for JS debugging, and Flipper for inspecting network requests, databases, and layout trees. For native-side issues, you use Android Studio (Logcat) or Xcode (Console/Instruments).

Flipper is a platform for debugging iOS, Android, and React Native apps. It provides a desktop interface to visualize and interact with your app. Key features include the 'Network' plugin for API monitoring, 'Layout' for inspecting components, and the 'Logs' plugin for consolidated system output.

Components are tested using 'Jest' as the test runner and 'React Native Testing Library' (RNTL) for rendering. RNTL focuses on testing components from the user's perspective (e.g., finding buttons by text rather than test IDs), ensuring that your tests remain resilient to internal implementation changes.

Jest is used for Unit and Integration testing, where components are rendered in a virtual environment (JSDOM). Detox is a 'Gray Box' End-to-End (E2E) testing framework that runs your app on a real device or emulator, simulating actual user interactions like tapping and scrolling.

Error Boundaries are class components that implement 'getDerivedStateFromError' or 'componentDidCatch'. They wrap around component trees to catch JavaScript errors in their child components, allowing you to display a fallback UI instead of letting the entire app crash on the user.

Production logging should avoid 'console.log' as it impacts performance. Instead, use breadcrumbs and crash reporting services like Sentry, Bugsnag, or Firebase Crashlytics. These tools capture the JS stack trace and device metadata to help you reproduce errors found in the wild.

Testing components that rely on APIs or Native Modules requires 'mocking'. You use 'jest.mock()' to replace real implementations with 'spy' functions. This ensures tests are deterministic and don't require a network connection or actual native hardware features (like the camera).

Code reviews ensure consistency in styling, verify that performance-heavy patterns (like large lists) are implemented correctly, and catch common pitfalls like missing 'useEffect' cleanups or improper bridge usage that could lead to memory leaks or UI jank.

Unit testing verifies a single function or component in isolation. Integration testing verifies how multiple components or services work together—for example, testing if a login form correctly calls the auth service and navigates to the dashboard upon success.

Snapshot tests capture the rendered output of a component and save it to a file. On subsequent runs, Jest compares the new output to the saved version. If they differ, the test fails, alerting you that the UI has changed unexpectedly.

You use 'act()' from the testing library to wrap the interaction or rendering. This ensures that all updates related to the effect are processed before you make assertions, preventing the common 'not wrapped in act' warning and ensuring reliable results.

RNTL discourages testing 'internals' (like state or instance methods) and encourages testing the 'user experience'. This results in tests that are less brittle; your tests won't break just because you renamed a variable, as long as the UI still works for the user.

Network requests are best debugged using Flipper's Network plugin or the 'React Native Debugger' app. You can also enable a global 'XMLHttpRequest' logger in your entry file to see requests in the console, though this is less detailed than dedicated tools.

Native Modules & Integration14

JavaScript modules contain logic that runs on the JS engine (Hermes/V8). Native modules are written in platform-specific languages (Java/Kotlin for Android, Swift/Obj-C for iOS) and provide access to hardware APIs or platform features that are not available in the standard React Native JS environment.

To create a native module, you define a class that extends 'ReactContextBaseJavaModule' (Android) or implements 'RCTBridgeModule' (iOS). You then use the @ReactMethod or RCT_EXPORT_METHOD macro to expose specific functions to JavaScript, allowing them to be called via 'NativeModules' in your JS code.

The Bridge is a message queue that serializes data into JSON to pass it between JS and Native threads. It is being replaced because it is asynchronous, single-threaded, and the serialization process creates a performance bottleneck for data-heavy interactions or high-frequency updates.

JSI is a lightweight, general-purpose layer written in C++ that allows the JavaScript engine to hold a reference to C++ host objects and invoke methods on them directly. It enables synchronous communication between JS and Native code, removing the need for JSON serialization and the Bridge.

TurboModules are the next-generation native modules that leverage JSI. They allow for 'lazy loading,' meaning a module is only initialized when it is first used, rather than all modules being initialized at app startup. This significantly improves app launch time and memory usage.

Fabric is React Native's new rendering system. It moves the UI operations into C++, allowing the JS thread to communicate directly with the UI thread. This enables synchronous layouts, improves performance for complex view hierarchies, and allows for better integration with host platform features like accessibility.

Integration involves adding the React Native library as a dependency (via Maven or CocoaPods), creating a 'ReactRootView' in the native code, and pointing it to your JS bundle. You must also ensure the Native and JS environments share the same lifecycle events for smooth transitions.

Using native components (via 'requireNativeComponent') is advantageous for performance-heavy UI elements like high-performance maps, video players, or custom camera filters where the overhead of the Bridge or JSI-based rendering might still be insufficient.

Permissions are handled by adding required strings to 'AndroidManifest.xml' (Android) and 'Info.plist' (iOS). Libraries like 'react-native-permissions' provide a JS API to check current status and request permission from the user at runtime with custom explanations.

The Info.plist is a configuration file in iOS apps that contains metadata about the application. It is where you define app permissions (like Camera or Location usage descriptions), supported orientations, and custom URL schemes for deep linking.

This is a mandatory file that describes essential information about the app to the Android build tools, the Android OS, and Google Play. It lists components like activities and services, and declares the permissions the app requires to function.

Fabric allows UI updates to be synchronous when necessary (like during a fast scroll or user typing). By moving the 'Shadow Tree' into C++ and sharing it with the native side, it avoids the 'asynchronous lag' seen in the old architecture where the UI could sometimes flicker or show white space.

'react-native link' was a manual command used in older versions to connect native libraries. 'Autolinking' (introduced in 0.60) handles this automatically by searching the node_modules during the build process and adding dependencies to the native projects without developer intervention.

Codegen is a tool that ensures type safety between JavaScript and Native code. It takes your TypeScript/Flow definitions and generates the required C++ boilerplate code for TurboModules and Fabric components, preventing runtime crashes due to type mismatches between the threads.

Push Notifications & Deep Linking8

Push notifications are usually implemented using Firebase Cloud Messaging (FCM) for Android and Apple Push Notification service (APNs) for iOS. Libraries like 'react-native-firebase' or 'expo-notifications' provide a unified API to handle token registration, background messages, and display notifications.

Remote (push) notifications are sent from a server via FCM or APNs even when the app is closed. Local notifications are triggered by the application itself on the device, usually based on a specific time or local event (like an alarm or a completed download).

Deep linking is implemented by configuring a custom URL scheme (e.g., myapp://) or Universal/App Links in the native project settings. In React Native, you use the 'Linking' API or React Navigation's 'linking' configuration to parse the URL and navigate to the corresponding screen.

Unlike custom URL schemes, Universal and App Links use standard 'https' URLs that are verified against a file hosted on your website (apple-app-site-association or assetlinks.json). If the app is installed, the link opens it directly; otherwise, it opens the website in the browser.

In the background, listeners provided by FCM can catch the data. In a quit state, you must use a 'Headless JS' task (on Android) or check the 'initialNotification' prop upon app launch to retrieve the notification data that triggered the app opening.

FCM is a cross-platform messaging solution that lets you reliably send messages at no cost. It acts as the intermediary between your server and the device, handling the complexities of maintaining connections and delivering payloads to both Android and iOS devices efficiently.

When the app is already in the foreground, the 'Linking' API's 'url' event listener is triggered. You must listen for this event in your root component and manually update the navigation state to push the new screen corresponding to the incoming deep link URL.

Headless JS is an Android-only feature used to run JavaScript tasks while the app is in the background. It is commonly used for syncing data in the background, handling geo-fencing events, or processing incoming push notifications that require logic before a UI is shown.

Environment & Configuration8

Environment variables are handled using libraries like 'react-native-config' or 'react-native-dotenv'. These tools allow you to define variables in a '.env' file (e.g., API_URL) and access them in your JS code, while also allowing the native layers to read them during the build process.

Metro is the JavaScript bundler for React Native. It takes all your JS files and their dependencies and combines them into a single file (the bundle) that the JS engine can execute. It also handles features like 'Fast Refresh' by only re-bundling changed modules during development.

Hot Reloading was an older feature that often led to inconsistent state. Fast Refresh is the modern implementation that is more resilient; it preserves the state of functional components and hooks while still performing a quick, partial reload of the edited modules.

This is done by creating multiple '.env' files and using 'build flavors' (Android) or 'schemes' (iOS). You configure the build process to pick the correct '.env' file based on the selected flavor/scheme, allowing for distinct API keys and configurations per environment.

It provides a unified way to access environment variables across JS, Java/Kotlin, and Objective-C/Swift. This is essential for configurations that need to be known by the native layer at compile-time, such as Google Maps API keys or deep-linking prefixes.

These are build configurations that allow you to create different versions of your app from the same codebase. For example, a 'Dev' flavor might have a different package name and icon than the 'Prod' flavor, enabling you to have both versions installed on the same device simultaneously.

API keys should never be hardcoded. They should be stored in environment variables. For extra security, sensitive keys should be kept on the backend, or 'Code Obfuscation' and 'ProGuard' should be used to make it harder for attackers to extract keys from the compiled binary.

Development builds include the Metro bundler connection, developer tools, and warnings, making them larger and slower. Production builds are optimized, minified, and have the JS engine's debugging capabilities stripped out to ensure maximum performance and security.

TypeScript8

Since React Native 0.71, TypeScript is the default. You use it by creating '.tsx' files. It provides static type checking, which catches errors during development. You define interfaces or types for props, state, and API responses, ensuring that data moving through your app follows a predictable structure.

The primary benefits are 'type safety' and 'enhanced IDE support.' TypeScript helps prevent common bugs like 'null is not an object' by enforcing type checks. It also makes refactoring easier and provides better autocompletion, which is invaluable in large codebases with complex data models.

Props are typed using an interface or type alias passed to the React.FC generic or directly in the destructured arguments. State is typed using generics with the useState hook: 'const [user, setUser] = useState<User | null>(null);'. This ensures 'user' can only be an object matching the User interface or null.

Interfaces are generally used for defining the shape of objects and support 'declaration merging' (extending by re-declaring). Types are more flexible; they can represent primitives, unions, and intersections. In React Native, both are used, but interfaces are often preferred for component props for performance and extendability.

Generics allow you to create reusable components or functions that work with multiple types while maintaining type safety. For example, a 'List' component can use a generic type <T> to ensure that the 'renderItem' function receives the correct object type regardless of whether it's a list of Users or Products.

Declaration Merging is a TypeScript feature where the compiler merges two separate declarations with the same name into a single definition. This is commonly used in React Native to extend existing modules or interfaces (like adding custom properties to the global 'ProcessEnv' or 'Theme' interfaces).

You define a 'Theme' interface, create a 'ThemeContext' that holds the current theme state, and wrap the app in a provider. Using TypeScript ensures that when you use 'colors.background', you only use valid color keys defined in your theme, preventing 'undefined' style errors.

Union types (e.g., 'type Status = "idle" | "loading" | "error"') allow a variable to have one of several types. This is extremely useful for API handling, as you can ensure the UI logic explicitly handles every possible state, making the code more robust and self-documenting.

Firebase & Third-Party Services5

Firebase is integrated using the 'React Native Firebase' library, which wraps the native Firebase SDKs for Android and iOS. This provides better performance and access to all Firebase features like Authentication, Firestore, and Cloud Messaging, compared to using the Firebase Web SDK in a JS environment.

Realtime Database is a single, large JSON tree optimized for low-latency syncing of simple data. Firestore is a document-collection based database that offers more powerful querying, better scalability, and a more structured data model, making it the preferred choice for most modern mobile applications.

It is a service that provides backend services and easy-to-use SDKs to authenticate users. It supports authentication using passwords, phone numbers, and popular identity providers like Google, Facebook, and Apple, handling the secure exchange of tokens and session management automatically.

Crashlytics is a lightweight, realtime crash reporter that helps you track, prioritize, and fix stability issues. It captures the JavaScript stack trace and native crash data in production, allowing you to see exactly where and why users are experiencing crashes in the wild.

It is a free app measurement solution that provides insight on app usage and user engagement. It automatically captures events like 'app_open' and allows you to define custom events to track specific user paths, helping you make data-driven decisions to improve your app's performance and retention.

Permissions & Security7

You should never store sensitive keys in plain text. Use environment variables during build time, and for runtime secrets, use the 'Keychain' (iOS) or 'Keystore' (Android) via libraries like 'react-native-keychain'. For maximum security, use an 'App Proxy' or 'BFF' (Backend for Frontend) to hide keys from the client entirely.

Obfuscation makes the compiled code difficult for humans to read, protecting your intellectual property and making it harder for attackers to find vulnerabilities. On Android, this is handled by 'ProGuard' or 'R8'. On iOS, it's more difficult, but tools like 'SwiftShield' or custom LLVM obfuscators can be used.

SSL Pinning is a technique where the app is hardcoded with the server's public key or certificate. This prevents 'Man-in-the-Middle' (MITM) attacks by ensuring the app only communicates with the legitimate server, even if the device's trust store has been compromised by a malicious certificate.

Permissions are handled by declaring them in the native config (Manifest/Info.plist) and then requesting them at runtime. The 'react-native-permissions' library is the standard for checking and requesting statuses (granted, denied, blocked) in a cross-platform way, providing a unified API for both OSs.

These are secure storage systems provided by the OS. Unlike AsyncStorage, which is just a file on disk, the Keychain/Keystore is encrypted and managed by the OS hardware security module (Secure Enclave). They are used to store passwords, biometric tokens, and encryption keys securely.

Biometrics are implemented using 'react-native-fingerprint-scanner' or 'expo-local-authentication'. These libraries invoke the native biometric prompt. If successful, they return a success callback or a token retrieved from the secure storage, allowing the user to log in without a password.

While CSP is a web concept, mobile apps use similar restrictions via 'App Transport Security' (iOS) and 'Network Security Configuration' (Android). These ensure the app only connects to specified domains over HTTPS, preventing the execution of code from untrusted sources or the leaking of data to malicious servers.

Internationalization & Localization5

React Native has built-in support for RTL. You use the 'I18nManager.allowRTL(true)' and 'I18nManager.forceRTL(true)' methods. Flexbox properties like 'flex-start' and 'flex-end' automatically flip when the app is in RTL mode, though you may need to adjust custom icons or absolute positioning manually.

i18next is a powerful internationalization framework. In React Native, it's used with 'react-i18next' to manage translation strings in JSON files. It handles pluralization, interpolation, and language switching dynamically, allowing the app to update the UI instantly when the user changes their language preference.

This library provides access to the user's device settings, such as their preferred language, region, currency, and temperature unit. It is used to detect the initial language of the app and to format numbers, dates, and currencies according to the user's local cultural standards.

Localized images are handled by creating a naming convention or a mapping object where the image source is determined by the current language code. For example, an image with English text would be swapped for a version with Spanish text when the app's locale is switched to 'es'.

Timezones are best handled by always storing and transmitting dates in UTC (ISO 8601). On the client, you use libraries like 'date-fns' or 'dayjs' to convert the UTC time to the user's local timezone for display, ensuring that events appear correctly regardless of where the user is located.

Build & Deployment27

Production builds require generating a signed binary. For Android, you use Gradle to generate an AAB (Android App Bundle) or APK. For iOS, you use Xcode to create an Archive. These builds are optimized for size and performance, with developer features like the Metro connection and 'yellow box' warnings removed.

Debug builds are for development, containing the Metro packager and supporting hot reloading. Release builds are minified, obfuscated, and bundled into a standalone package. Release builds run significantly faster because they don't have the overhead of the debugger and use optimized native code.

An APK (Android Package) is the traditional format for direct installation. An AAB (Android App Bundle) is the modern standard for Google Play. AAB allows Google to perform 'Dynamic Delivery,' where they serve only the specific code and assets needed for a user's device, resulting in smaller download sizes.

An IPA (iOS App Store Package) is generated through Xcode by creating an 'Archive.' Once the archive is successful, you 'Distribute App' and select the 'App Store Connect' or 'Ad Hoc' method. This process requires a valid Apple Developer Program membership and proper provisioning profiles.

App signing is a security measure that ensures the code has not been altered since it was signed. Android uses Keystores (.jks), while iOS uses Certificates and Provisioning Profiles. Without a valid signature, mobile operating systems will refuse to install the application for security reasons.

A CI/CD pipeline is implemented using tools like GitHub Actions, Bitrise, or App Center. The pipeline automatically runs tests (Jest), lints code, and builds the binaries (AAB/IPA) whenever code is pushed. It then automatically uploads the builds to TestFlight or Google Play Internal Testing.

CodePush (part of Microsoft App Center) allows you to push JavaScript and asset updates directly to users' devices without going through the App Store review process. It works by hosting your JS bundle on a server; when the app starts, it checks for updates and downloads the new bundle dynamically.

OTA updates allow you to fix bugs and update content instantly. In React Native, this is possible because the logic is in JavaScript. However, OTA updates cannot be used if you change any native code (Java/Swift/C++), as those changes require a full app store binary update.

Fastlane is an open-source tool that automates the tedious parts of mobile deployment. It can take screenshots, manage provisioning profiles, build the app, and upload it to the stores with a single command, significantly reducing the human error associated with manual releases.

You manage them through the Apple Developer portal or Xcode's 'Automatically manage signing.' Certificates identify you as a developer, while Provisioning Profiles link your certificate, your app ID, and the devices the app can run on. They are essential for 'Ad Hoc' and 'App Store' distribution.

TestFlight (iOS) and Internal Testing (Android) are platforms for beta testing. They allow you to share your app with up to 10,000 testers before a public release. This is crucial for catching bugs on various device models and OS versions that you may not have tested locally.

Rejections are handled by reviewing the specific guideline violated (e.g., Guideline 2.1 - App Completeness). Common issues include crashes, lack of a 'Delete Account' button, or improper use of background permissions. You must fix the issue and submit a new build or appeal the decision with more information.

Ad Hoc distribution allows you to install the app on a specific list of registered devices (UDIDs) for testing purposes. App Store distribution is for the general public and requires a review process by Apple. Ad Hoc is limited to 100 devices per year, whereas App Store has no limit.

ProGuard and its successor, R8, are tools that shrink, optimize, and obfuscate your code. They remove unused code (tree-shaking) and rename classes and variables to shorten names, which reduces the APK size and makes reverse-engineering the application much more difficult for attackers.

Multi-Dex is required when an Android app exceeds the 65,536 method limit (the '64k limit'). For modern React Native apps, this is enabled by default in 'build.gradle'. It allows the APK to contain multiple .dex files, enabling the use of large numbers of libraries and complex codebases.

A Scheme defines a collection of targets to build, a configuration to use (Debug/Release), and an executable to launch. You use different schemes to manage different build environments, such as one scheme for 'Dev' with different API endpoints and another for 'Prod.'

Microsoft App Center allows you to build your app in the cloud and distribute it to testers via an email link. It also provides 'Analytics' and 'Diagnostics' (crash reports) similar to Firebase, making it a comprehensive solution for the entire mobile development lifecycle.

The Bundle ID (iOS) and Package Name (Android) are unique strings (e.g., com.company.app) that identify your app globally on the device and in the stores. Once an app is published, these identifiers cannot be changed without creating a completely new app listing.

Privacy Manifests (PrivacyInfo.xcprivacy) are files required by Apple to declare the types of data your app and its third-party SDKs collect. You must list all 'Required Reason APIs' and data tracking practices to comply with Apple's transparency rules during the submission process.

The Version Number (e.g., 1.0.0) is what users see in the store. The Build Number (e.g., 42) is an internal counter used to distinguish between different builds of the same version. Every time you upload a new binary to the store, the build number must be incremented.

A Keystore is a file containing the private key used to sign your Android app. If you lose it, you cannot update your app on Google Play. It must be stored securely (not in Git), and the passwords should be managed using environment variables or a secret manager.

Automating screenshots is done using Fastlane 'Snapshot' (iOS) and 'Screengrab' (Android). These tools run UI tests that navigate through the app and capture screens on various device sizes automatically, ensuring consistent and professional store listings in all languages.

Internal is for your immediate team (up to 100 users). Alpha is for a larger group of trusted testers. Beta is for an open group of users from the public. Each track provides a progressively wider circle of testing to ensure stability before the 'Production' release.

App Store Connect is the web portal used to manage iOS apps. It is where you upload builds, set up store metadata (descriptions, keywords), manage pricing, and view sales and crash reports. It is the final gatekeeper for releasing any app to the Apple ecosystem.

The Google Play Console is the dashboard for Android developers. It provides tools for publishing apps, monitoring performance, and responding to user reviews. It also includes the 'Pre-launch Report,' which tests your app on real devices in Google's data centers for crashes and layout issues.

ProGuard (and R8) is a tool that shrinks and obfuscates your Java/Kotlin code. It removes unused classes and renames methods to short, cryptic strings. This significantly reduces the APK size and makes it much more difficult for someone to reverse-engineer your app's native logic.

Tree Shaking is the removal of unused code from the final bundle. While standard Webpack/Vite supports this well, Metro (React Native's bundler) has limited support for it. To optimize, you should use 'babel-plugin-transform-imports' to ensure you only import the specific functions you need from large libraries.

Additional Important Topics13

User sessions are managed by storing an 'Access Token' (JWT) in 'react-native-keychain'. You use an 'Axios Interceptor' to attach the token to every request. If the token expires (401 error), the interceptor triggers a 'Refresh Token' flow to get a new session without forcing the user to log in again.

React Native Paper is strictly following Material Design guidelines and is very lightweight. NativeBase is a more flexible component library that offers 'Utility First' styling similar to Tailwind CSS. Both simplify UI development, but Paper is often preferred for performance and Material-specific apps.

The <ActivityIndicator /> is a core component that shows a platform-specific circular spinner. You use a boolean state (e.g., 'isLoading') to conditionally render the indicator while an API call is in progress, ensuring the user knows the application is working and hasn't frozen.

Android's back button is managed using the 'BackHandler' API. You add a listener to 'hardwareBackPress'. If you are using React Navigation, it handles the stack 'pop' automatically, but you may need 'BackHandler' for custom logic like showing an 'Exit App?' confirmation dialog.

You use the 'RefreshControl' component. It is passed to the 'refreshControl' prop of ScrollView or FlatList. You provide an 'onRefresh' function and a 'refreshing' boolean state to show the native loading indicator while data is being re-fetched from the server.

Authentication is typically handled using JWT (JSON Web Tokens). After the user logs in, the token is stored in secure storage (Keychain/Keystore). A 'Root Navigator' then uses a conditional 'isLoggedIn' state to show either the 'Auth' stack or the 'App' stack.

Sessions should use short-lived access tokens and long-lived refresh tokens. Tokens should be stored in 'Keychain' to prevent unauthorized access. You should also implement 'Auto-Logout' on 401 errors and 'Session Timeout' logic for apps handling sensitive financial or medical data.

NativeBase is a UI component library that provides a unified set of components for React Native. It is themed using a 'utility-first' approach similar to Tailwind CSS, allowing for rapid UI development with a focus on accessibility and consistency across platforms.

React Native Elements is a toolkit that provides a consistent UI design across Android and iOS. It is more 'opinionated' than the core components but less restrictive than Material-only libraries, offering a wide range of pre-styled components like SearchBars, PricingCards, and Tooltips.

You wrap your data-dependent content in a conditional check. While the 'loading' state is true, return the <ActivityIndicator /> component. Once data is received, set 'loading' to false to render the actual content, providing a smooth experience while waiting for network responses.

ActivityIndicator is the platform-specific progress indicator. On iOS, it shows the 'Grey Daisy' spinner, and on Android, it shows the Material Design circular loader. It is the most common way to show 'in-progress' status for background tasks or initial page loads.

Backward navigation is handled by the navigation library (like React Navigation). It maintains a stack of screens. Calling 'navigation.goBack()' pops the current screen off the stack. On Android, the physical back button also triggers this 'pop' action by default.

BackHandler is a React Native API used specifically for Android to detect hardware back button presses. It allows you to override the default back behavior (e.g., preventing the user from leaving a form with unsaved changes) or closing custom modals and drawers manually.

Related