React Native

Introduction to React Native -  Learn everything about React Native


Introduction

React Native is a framework created by Facebook that lets developers construct apps, for smartphones using JavaScript and React library. A favorite, among front end developers.This tool is commonly employed to make applications that function on both iOS and Android devices with one set of code simplifying cross platform app development. 

What is React Native?

React Native essentially allows developers to create apps using elements instead of web components, as the foundation. It harnesses the React component structure. Merges it with features specific to native platforms to give apps an authentic native appearance and operation. In contrast to applications that depend on WebView (such as Apache Cordova) React Native applications employ genuine native components, for enhanced efficiency and more seamless user interactions.

Key Features:

  • Cross-Platform Development: Write once, run on both iOS and Android.
  • Reusable Components: Build components that can be reused across different screens and projects.
  • Hot Reloading: See changes in real-time without losing the app's state.
  • Access to Native Modules: Extend functionality with platform-specific code when necessary.

How to install React Native

To get started with React Native, you have two main ways to set up your environment:

  1. Using Expo CLI (Recommended for beginners)
  2. Using React Native CLI (For more control and access to native modules)

Option 1: Installing React Native Using Expo CLI

Expo is a great option if you want a quick and easy setup without worrying about configuring native code for iOS and Android. It’s ideal for beginners or developers focusing on JavaScript-only features.

Prerequisites

Step 1: Install Expo CLI

Open your terminal and run:

npm install -g expo-cli 

You can also use yarn if it's your preferred package manager:

yarn global add expo-cli

 

Step 2: Create a New React Native Project

Now, create your first React Native project:

expo init MyFirstApp

 

You will be asked to select a template option (for example; Blank or Blank (TypeScript)).

Navigate into your project directory:

cd MyFirstApp

 

Step 3: Start the Development Server

Run the following command to start the app:

npm start

 

This will automatically launch a new tab in your browser with the Expo Dev Tools. You can then scan the QR code shown using the Expo Go app-available on both iOS and Android-or run your app on your physical device.

Alternatively, use:

npx expo start

 

Step 4: Running on a Device or Emulator

Android: If you have an Android emulator installed (like Android Studio), press a to launch it.

iOS: If you're on a Mac with Xcode installed, press i to open the iOS simulator.

Option 2: Installing React Native Using React Native CLI

Prerequisites

  • Node.js (LTS version recommended)
  • Java Development Kit (JDK) for Android development
  • Android Studio for Android emulators
  • Xcode (macOS only) for iOS development

Step 1: Install the React Native CLI

First, install react-native globally:

npm install -g react-native 

Step 2: Create a New React Native Project

In your terminal, run:

npx react-native init MyFirstApp

This will create a new project named MyFirstApp.

Step 3: Running the App

Navigate to your project folder:

cd MyFirstApp

To run the app on an Android emulator or a connected device:

npx react-native run-android

To run the app on the iOS simulator (macOS only):

npx react-native run-ios

Note: Please check your Android emulator or iOS simulator running before executing the above commands.

Step 4: Troubleshooting React Native

If you come across problems, with your setup or functionality is not working as expected in cases it is due, to either requirements or incorrect settings and setups. Refer to the official React Native documentation for troubleshooting steps: React Native Docs

Conclusion

Whether you use Expo or React Native CLI depends on your project's needs. Expo is great for rapid development, especially for beginners, while the React Native CLI provides full control and flexibility for more complex apps.

React Native Components and Styling

Components

Actually, components are the building blocks of your application in React Native. Components allow breaking up the UI into independent and reusable pieces, where each piece is considered in isolation. React Native supports two types of components:

  • Functional Components - Use functions and React hooks.
  • Class Components - Use ES6 classes and lifecycle methods (less common nowadays).

Example: Functional Component

import React from 'react';import { View, Text, Button, StyleSheet } from 'react-native';const Greeting = ({ name }) => ( <View style={styles.container}> <Text style={styles.text}>Hello, {name}!</Text> </View>);const App = () => ( <View> <Greeting name="John" /> </View>);const styles = StyleSheet.create({ container: { padding: 20, backgroundColor: '#f0f8ff' }, text: { fontSize: 18, color: '#333' },});export default App; 

Core Components

  • View :A container for layout and organizing elements.
  • Text :Displays text content.
  • Image :Renders images from local files or URLs.
  • TextInput :Input field for user input.
  • ScrollView :A scrollable container for overflowing content.
  • FlatList :Optimized list for large data sets.
  • TouchableOpacity :Wrapper for touch events with opacity feedback.

Styling in React Native

React Native uses a CSS-like styling approach but relies on JavaScript objects. Styling can be done inline or using StyleSheet.

Example: Styling with StyleSheet

import { StyleSheet, View, Text } from 'react-native';const App = () => ( <View style={styles.container}> <Text style={styles.title}>Styled Component</Text> </View>);const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 24, fontWeight: 'bold', color: '#4CAF50', },});export default App;

 

Flexbox Layout

React Native uses Flexbox for layout, making it easy to create responsive designs.

<View style={(flex: 1. flexDirection: row', justifyContent: 'space-around' }}> <View style={{ width: 50, height: 50, backgroundColor: 'red' }} /> <View style={{ width: 50, height: 50, backgroundColor: 'green'}} /> <View style=[{ width: 50, height: 50, backgroundColor: 'blue' /> </View> 

React Native Navigation

To navigate between screens, React Native developers commonly use the React Navigation library.

Setting Up React Navigation

  • Install the necessary packages:
npm install @react-navigation/native @react-navigation/native-stack npm install react-native-screens react-native-safe-area-context  
  • Create a Stack Navigator:
import React from 'react';import { NavigationContainer } from '@react-navigation/native';import { createNativeStackNavigator } from '@react-navigation/native-stack';import HomeScreen from './HomeScreen';import DetailsScreen from './DetailsScreen';const Stack = createNativeStackNavigator();const App = () => ( <NavigationContainer> <Stack.Navigator initialRouteName="Home"> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> </NavigationContainer>);export default App;

React Native leverages React hooks like useState and useReducer for managing component state. For global state, we can use Context API or libraries like Redux.

Local State with Hooks

import React, { useState } from 'react';import { View, Text, Button } from 'react-native';const Counter = () => { const [count, setCount] = useState(0); return ( <View> <Text>Count: {count}</Text> <Button title="Increment" onPress={() => setCount(count + 1)} /> </View> );};export default Counter; 

Global State with Context API

import React, { useContext, useState } from 'react';import { View, Button } from 'react-native';const AppContext = React.createContext();const AppProvider = ({ children }) => { const [user, setUser] = useState(null); return ( <AppContext.Provider value={{ user, setUser }}> {children} </AppContext.Provider> );};const HomeScreen = () => { const { user, setUser } = useContext(AppContext); return ( <View> <Button title="Login" onPress={() => setUser('John')} /> </View> );};export { AppProvider, HomeScreen };

 

Redux for Complex State Management

npm install @reduxjs/toolkit react-redux 

APIs and Data Fetching

Fetching data is essential for most apps. React Native uses JavaScript's fetch API, but you can also use libraries like axios.

Fetching Data with Fetch API

import React, { useEffect, useState } from 'react';import { View, Text, ActivityIndicator, FlatList } from 'react-native';const App = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then((json) => { setData(json); setLoading(false); }) .catch((error) => { console.error(error); setLoading(false); }); }, []); return ( <View style={{ padding: 20 }}> {loading ? ( <ActivityIndicator size="large" color="#0000ff" /> ) : ( <FlatList data={data} keyExtractor={(item) => item.id.toString()} renderItem={({ item }) => <Text>{item.title}</Text>} /> )} </View> );};export default App; 

Handling Errors

 

try { const response = await fetch('https://api.example.com/data'); if (!response.ok) throw new Error('Network response was not ok'); const data = await response.json();} catch (error) { console.error('Error fetching data:', error);} 

Using Axios for Fetching Data

If you prefer using Axios:

npm install axios 

Working with Native Features

React Native lets you use features of your device, such as the camera, GPS and file storage through built-in tools or third party libraries.

 

Accessing Device Features with Libraries

The react-native ecosystem includes many libraries to access native device features:

  • Camera: react-native-camera, react-native-vision-camera

  • Location: react-native-geolocation-service

  • File System: react-native-fs

  • Push Notifications: react-native-push-notification

Example 1: Accessing the Camera

For reaching the camera of the device, you can use the react-native-vision-camera package. This gives access to the camera that is modern and performant.

  • Install the library:
npm install react-native-vision-camera
  • Permissions Setup:

On iOS, update the Info.plist: <key>NSCameraUsage Description</key> <string>We need your permission to use the camera</string>

  • On Android, update the AndroidManifest.xml: <uses-permission android:name="android.permission.CAMERA"/> 
    • Using the Camera in your component:
    import { Text, View, Button } from 'react-native';import React, { useEffect, useState } from 'react';import { Camera, useCameraDevices } from 'react-native-vision-camera';const CameraScreen = () => { const devices = useCameraDevices(); const device = devices.back; useEffect(() => { (async () => { const status = await Camera.requestCameraPermission(); if (status !== 'authorized') alert('Camera permission required'); })(); }, []); if (device == null) return <Text>Loading...</Text>; return ( <Camera style={{ flex: 1 }} device={device} isActive={true} /> );};export default CameraScreen;

     

     Example 2: Getting the User’s Location

    Install the geolocation service:

    npm install react-native-geolocation-service

    Get user’s current location:

    import React, { useEffect, useState } from 'react';import { View, Text, Button, PermissionsAndroid } from 'react-native';import Geolocation from 'react-native-geolocation-service';const LocationExample = () => { const [location, setLocation] = useState(null); const requestPermission = async () => { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION ); return granted === PermissionsAndroid.RESULTS.GRANTED; }; const getLocation = async () => { const hasPermission = await requestPermission(); if (hasPermission) { Geolocation.getCurrentPosition( (position) => setLocation(position.coords), (error) => console.error(error), { enableHighAccuracy: true } ); } }; useEffect(() => { getLocation(); }, []); return location ? ( <Text>Latitude: {location.latitude}, Longitude: {location.longitude}</Text> ) : ( <Text>Fetching location...</Text> );};export default LocationExample;

    Performance Optimization

    Ensuring your React Native app performs smoothly is crucial, especially on older devices. Here are some best practices to optimize performance:

    Best Practices for Performance Optimization

    • Use FlatList for large lists instead of ScrollView.

    • Avoid unnecessary re-renders by using React.memo, useMemo, and useCallback.

    • Optimize images with libraries like react-native-fast-image.

    • Use shouldComponentUpdate in class components or React.memo for functional components to avoid unnecessary re-renders.

    • Enable Hermes (a JavaScript engine optimized for React Native) to reduce startup times.

    Example: Optimizing FlatList with Memoization

    import React, { memo } from 'react';import { FlatList, Text, View } from 'react-native';const Item = memo(({ item }) => { console.log('Rendering item', item.id); return <Text>{item.name}</Text>;});const App = () => { const data = Array.from({ length: 1900 }, (_, index) => ({ id: index + 1, name: `Item ${index + 1}`, })); return ( <FlatList data={data} renderItem={({ item }) => <Item item={item} />} keyExtractor={(item) => item.id.toString()} /> );};export default App; 

    Animations

    Animations make an app look smoothened and interactive. By using the Animated API or LayoutAnimation, or even a third-party library like react-native-reanimated, you are able to give your application life with fun interactivity.

    Using the Animated API

    import React, { useRef, useEffect } from 'react';import { Animated, View } from 'react-native';const FadeInView = () => { const fadeAnim = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.timing(fadeAnim, { toValue: 1, duration: 2000, useNativeDriver: true, }).start(); }, []); return ( <Animated.View style={{ opacity: fadeAnim }}> <View style={{ width: 200, height: 200, backgroundColor: 'skyblue' }} /> </Animated.View> );};export default FadeInView;  

    Using react-native-reanimated

    react-native-reanimated is a more performant option for complex animations.

    npm install react-native-reanimated 

    Testing and Debugging

    Testing and debugging are essential to ensuring your app is reliable and bug-free.

    Debugging Tools

    • React Native Debugger: A standalone tool that combines Redux DevTools with React DevTools.

    • Flipper: A desktop app that helps visualize and debug React Native apps.

    Using console.log and Breakpoints

    • Add console.log statements to check variable values.

    • Use breakpoints in Visual Studio Code by clicking the gutter next to a line number.

    Unit Testing with Jest

    React Native apps commonly use Jest for unit testing.

    • Install Jest: npx jest --init 
    • Write a Test Case:
    import React from 'react';import renderer from 'react-test-renderer';import App from '../App';test('renders correctly', () => { const tree = renderer.create(<App />).toJSON(); expect(tree).toMatchSnapshot();});

     

    End-to-End Testing with Detox

    Detox is a powerful end-to-end testing tool for React Native.

    • Install Detox:
    npm install -g detox-cli npm install detox
    • Configure Detox: Add configuration to package.json:
    "detox": { "testRunner": "jest", "configurations": { "ios": { "device": { "type": "iPhone 12" }, "app": "ios/build/Build/Products/Debug-iphonesimulator/MyApp.app" } }} 
    • Write a Detox Test:
    describe('App Tests', () => { beforeAll(async () => { await device.launchApp(); }); it('should show welcome screen', async () => { await expect(element(by.id('welcome'))).toBeVisible(); });});

     

    Deployment & Distribution

    Making your React Native application ready for end use is a very critical activity. However, publishing an app across iOS and Android differs. Let's break down how to publish your app on each so that people can download and use it.

    iOS Deployment

    To upload your iOS App to the App Store, you will need access to a Mac and an Apple Developer account.

    Steps for iOS DeploymentGo to App Store Connect, create a new app record, and submit your build for review.

    1. Create an App Store Connect Account:

    2. Generate Certificates & Profiles:

      • Open Xcode. Now, go to Preferences > Accounts.

      • Create an iOS Distribution Certificate and Provisioning Profile.

    3. Prepare Your App:

      • In your React Native project, open the ios folder using Xcode.

      • Update the Bundle Identifier to match your app’s identifier.

      • Set your Build Configuration to Release.

    4. Archive and Distribute:

      • In Xcode, select Product > Archive.

      • Once archived, click Distribute App and follow the steps to upload to App Store Connect.

    5. Submit for Review:

      • Go to App Store Connect, create a new app record, and submit your build for review.Archive and Distribute:

    Making your React Native application ready for end use is a very critical activity. However, publishing an app across iOS and Android differs. Let's break down how to publish your app on each so that people can download and use it.

    iOS Deployment

    To upload your iOS App to the App Store, you will need access to a Mac and an Apple Developer account.

    Steps for iOS DeploymentGo to App Store Connect, create a new app record, and submit your build for review.

    1. Create an App Store Connect Account:

    2. Generate Certificates & Profiles:

      • Open Xcode. Now, go to Preferences > Accounts.

      • Create an iOS Distribution Certificate and Provisioning Profile.

    3. Prepare Your App:

      • In your React Native project, open the ios folder using Xcode.

      • Update the Bundle Identifier to match your app’s identifier.

      • Set your Build Configuration to Release.

    4. Archive and Distribute:

      • In Xcode, select Product > Archive.

      • Once archived, click Distribute App and follow the steps to upload to App Store Connect.

    5. Submit for Review:

      • Go to App Store Connect, create a new app record, and submit your build for review.Archive and Distribute:

    Example Command to Build iOS App

    cd iosnpx pod-installxcodebuild -scheme "MyApp" -configuration Release archive -archivePath MyApp.xcarchive

     

    Android Deployment

    To deploy an Android app, you'll need to generate a signed APK or AAB (Android App Bundle).

    Steps for Android Deployment

    Generate a Keystore:

    keytool -genkeypair -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias

     

    Update gradle.properties: Add the keystore details:

    MYAPP_UPLOAD_STORE_FILE=my-release-key.jksMYAPP_UPLOAD_KEY_ALIAS=my-key-aliasMYAPP_UPLOAD_STORE_PASSWORD=your-store-passwordMYAPP_UPLOAD_KEY_PASSWORD=your-key-password
    • Build the APK or AAB:
    cd android./gradlew clean./gradlew assembleRelease
    • Upload to Google Play Console:

    Create a new application on the Google Play Console.

    Upload your app-release.aab file.

    1. Organize Project Structure

    Ensuring a well-structured project layout is essential to enhance the scalability and maintainability of your React Native app. Segmenting your codebase into logical modules, components, and screens is crucial. For instance, consider organizing your project in the following manner:

     

    src ├── components/ │ ├── Button.js │ ├── Header.js ├── screens/ │ ├── HomeScreen.js │ ├── ProfileScreen.js ├── utils/ │ ├── api.js ├── App.js

     

    This method will make development faster and help create apps more smoothly and efficiently.

    Keeping things organized by separating different parts of your app is key. It helps developers focus on specific features without confusion or conflicts. This method boosts teamwork, speeds up development, and leads to better results.

    2. Use Functional Component

    Since the advent of React hooks, functional components have taken the lead as the preferred approach for writing components in React Native. Their readability, testability, and maintainability make them a standout choice.

    Whenever possible, opt for functional components over class components, and leverage the potential of hooks like ‘useState’, ‘useEffect’, and ‘useContext’ to effectively manage state and handle side-effects in your application. This way, you can harness the true power of React Native development.

    3. Optimise Images

    When developing mobile apps, you must be aware of the image assets you include. If they are optimised, they can positively impact the app’s performance. To justify this, it’s recommended to use tools for compressing and resizing images before adding them to your project. Furthermore, React Native’s ‘Image’ component is an excellent resource for caching and efficiently loading images with various options.

    4. Minimal use of Third-Party libraries

    When developing an app, third-party libraries can help accelerate the process. However, using them in small quantities is essential to avoid bloating the app and causing conflicts or performance problems. Before including a library, it’s necessary to consider its relevance and make sure it’s being regularly maintained and updated. Additionally, keep an observant watch on the app’s bundle size to prevent any unnecessary extra weight caused by adding new libraries.

    5. Memory Management

    Managing memory efficiently is essential when using mobile devices due to limited resources. To prevent memory leaks, clean up event listeners, timers, and subscriptions when components unmount. To handle this, you can use the cleanup function in the ‘useEffect’ hook. Additionally, it’s essential to be conscious of large data sets in memory, so consider using pagination or lazy-loading techniques when dealing with extensive lists or images.

    6. Optimise Performance for Flatlist

    When displaying extensive data lists, ‘FlatList’ is the ideal component for efficient rendering. However, proper usage can result in good performance. To ensure that React identifies items accurately, it is vital to supply a distinctive ‘keyExtractor’ prop. To optimise the rendering process for lengthy lists, consider using the ‘getItemLayout’ prop or ‘initialNumToRender’.

    7. Use React Native debugger

    If you want to inspect and debug your app’s components and state, React Native Debugger is a powerful tool to use. It provides a top-notch development experience and can help you identify issues such as performance bottlenecks and state management problems.

    8. Stay Updated

    Keeping up-to-date with the frequent updates and improvements of React Native ensures optimal performance, security, and access to the latest features. These can be achieved by following the official documentation and community forums, attending conferences or webinars, and regularly upgrading your app to the newest version of React Native.