DEV Community

Ajmal Hasan
Ajmal Hasan

Posted on • Edited on

Master Lazy Loading in React Native/ReactJS

Image description
In today's mobile app development landscape, delivering a fast and seamless user experience is essential. As React Native apps grow larger, bundle sizes can increase significantly, leading to slower load times and reduced performance. Code splitting and lazy loading are two powerful optimization techniques that help mitigate these issues by loading only the code required for the current view, thereby improving load times and overall app performance.

This article explores code splitting and lazy loading in React Native, their benefits, and practical use cases for optimizing app performance.

Why Lazy Loading?

Lazy loading ensures that only the necessary parts of an application are loaded when needed, reducing initial load times and improving the overall user experience. It’s especially useful for larger applications with numerous components or screens that may not be accessed frequently.


Key Benefits of Code Splitting and Lazy Loading

  1. Faster Initial Load Time: Only essential code is loaded initially, which speeds up the app's startup.
  2. Improved Performance: Fewer resources loaded at startup mean smoother performance overall.
  3. Reduced Memory Usage: Loading only required components or screens reduces the memory footprint.
  4. Optimized Network Usage: Lazy loading ensures only necessary data is fetched, minimizing network requests.

1) Use Cases for Lazy Loading in React Native

Lazy Loading Screens and Components (Code Splitting)

Lazy loading is commonly used in React Native for screens and components that aren't accessed frequently. This reduces the initial bundle size and improves performance.

Example: Normal Component Loading

In this example, all components are loaded at once when the app starts, which increases the initial load time.

import React from 'react';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';

const App = () => {
  return (
    <>
      <HomeScreen />
      <ProfileScreen />
    </>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Example: Lazy Loading Components

Here, React.lazy() is used to load components only when needed, improving performance by reducing the initial load time.

import React, { Suspense, lazy } from 'react';
import { ActivityIndicator } from 'react-native';

const HomeScreen = lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = lazy(() => import('./screens/ProfileScreen'));

const App = () => {
  return (
    <Suspense fallback={<ActivityIndicator size="large" color="#0000ff" />}>
      <HomeScreen />
      <ProfileScreen />
    </Suspense>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Differences Between Normal and Lazy Loading

Feature Normal Loading Lazy Loading
Loading Strategy Loads everything upfront Loads components/resources as needed
Initial Load Time Longer Shorter
Memory Usage Higher, as all components are loaded upfront Lower, as only needed components are loaded
User Experience Slower startup but no delays during navigation Faster startup with slight delays when loading components

2) Lazy Loading in Navigation (React Navigation)

Lazy loading can also be applied to navigation. Screens are loaded only when accessed, reducing initial bundle size and improving performance.

Example: Lazy Loading Screens with Stack Navigator

import React, { Suspense, lazy } from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import { ActivityIndicator } from 'react-native';

const HomeScreen = lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = lazy(() => import('./screens/ProfileScreen'));

const Stack = createStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Home"
          component={() => (
            <Suspense fallback={<ActivityIndicator size="large" color="#0000ff" />}>
              <HomeScreen />
            </Suspense>
          )}
        />
        <Stack.Screen
          name="Profile"
          component={() => (
            <Suspense fallback={<ActivityIndicator size="large" color="#0000ff" />}>
              <ProfileScreen />
            </Suspense>
          )}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

3) Lazy Loading Images

In React Native, lazy loading images can save memory and bandwidth, especially for apps with numerous or large images.

Example: Lazy Loading Images Using react-native-fast-image

react-native-fast-image offers optimized image loading, with lazy loading capabilities built-in.

npm install react-native-fast-image
Enter fullscreen mode Exit fullscreen mode
import React from 'react';
import { ScrollView, Text } from 'react-native';
import FastImage from 'react-native-fast-image';

const LazyLoadingImages = () => {
  return (
    <ScrollView>
      <Text>Scroll down to load images</Text>
      <FastImage
        style={{ width: 200, height: 200 }}
        source={{ uri: 'https://example.com/my-image1.jpg' }}
        resizeMode={FastImage.resizeMode.contain}
      />
      <FastImage
        style={{ width: 200, height: 200 }}
        source={{ uri: 'https://example.com/my-image2.jpg' }}
        resizeMode={FastImage.resizeMode.contain}
      />
    </ScrollView>
  );
};

export default LazyLoadingImages;
Enter fullscreen mode Exit fullscreen mode

4) Lazy Loading Redux Reducers

With Redux, you can dynamically inject reducers only when needed, reducing the initial store size.

Example: Lazy Loading Redux Reducers

// Helper function to inject a new reducer dynamically
export function injectReducer(key, asyncReducer) {
  if (!store.asyncReducers[key]) {
    store.asyncReducers[key] = asyncReducer;
    store.replaceReducer(createReducer(store.asyncReducers));
  }
}
Enter fullscreen mode Exit fullscreen mode

5) Lazy Loading Libraries and Data

Lazy loading third-party libraries and large datasets can further improve app performance.

Example: Lazy Loading a Library

import React, { lazy, Suspense, useState } from 'react';

const HeavyComponent = lazy(() => import('heavy-library'));

const App = () => {
  const [showComponent, setShowComponent] = useState(false);

  return (
    <View>
      <Button title="Load Component" onPress={() => setShowComponent(true)} />
      {showComponent && (
        <Suspense fallback={<Text>Loading...</Text>}>
          <HeavyComponent />
        </Suspense>
      )}
    </View>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Example: Lazy Loading Data

import React, { useState, useEffect } from 'react';
import { FlatList, ActivityIndicator, Text } from 'react-native';

const LazyLoadData = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(json => {
        setData(json);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <ActivityIndicator />;
  }

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item.name}</Text>}
      keyExtractor={item => item.id}
    />
  );
};

export default LazyLoadData;
Enter fullscreen mode Exit fullscreen mode

Conclusion

Lazy loading and code splitting are essential techniques for optimizing React Native apps. By loading only the necessary components, screens, libraries, or data when needed, you can significantly reduce initial load times, improve performance, and create a smoother user experience.

Top comments (0)