DEV Community

Cover image for Lazy Loading in React Native: Beyond the Basics
naly moslih
naly moslih

Posted on

Lazy Loading in React Native: Beyond the Basics

Introduction

Lazy loading is often discussed in the context of React Native, but most resources only scratch the surface. In this article, we'll dive deep into the practical applications of lazy loading in mobile app development, showcasing techniques and scenarios not widely covered.

We'll explore:

1- Lazy loading in specific contexts like offline-first apps.

2- Techniques for conditional lazy loading.

3- Using lazy loading with animations.

4- Optimizing large paginated views with lazy loading.

5- Insights from real-world experiences (some you might not find elsewhere).

What Makes Lazy Loading More Than Just a Buzzword?

Lazy loading isn't just a technical optimization; it reflects how user interaction shapes app architecture. It’s about understanding user behavior to prioritize critical content while deferring non-essential elements.

Real-world insight: In a food delivery app I worked on, optimizing lazy loading for restaurant menus was a game-changer. Loading large images of items only when they were scrolled into view not only saved memory but also ensured a seamless browsing experience.

Going Beyond React.lazy: Real Use Cases

1.** Lazy Loading and Offline-First Apps**
For apps designed to work offline, lazy loading gets tricky. Components need to be available without an internet connection, but you can still defer rendering non-essential parts.

Unique Technique: Prefetching for Offline Use

Instead of simply lazy loading, combine lazy loading with prefetching. Here's how:

import React, { useState, useEffect, lazy, Suspense } from 'react';
import { View, Text, Button } from 'react-native';

const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => {
  const [isReadyOffline, setIsReadyOffline] = useState(false);

  useEffect(() => {
    // Simulate prefetching and offline preparation
    const timer = setTimeout(() => setIsReadyOffline(true), 2000);

    return () => clearTimeout(timer);
  }, []);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      {isReadyOffline ? (
        <Suspense fallback={<Text>Loading...</Text>}>
          <LazyComponent />
        </Suspense>
      ) : (
        <Text>Preparing offline resources...</Text>
      )}
    </View>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode
  1. Optimizing Large Paginated Views with Lazy Loading

If your app has large content spread across multiple pages, lazy loading can be a powerful tool. For example, when using a PagerView component, you can optimize rendering by wrapping pages with lazy-loaded logic.

Example: Wrapping PagerView for Large Content

import React, { lazy, Suspense } from 'react';
import { Text, View } from 'react-native';
import PagerView from 'react-native-pager-view';

// Lazy load pages
const PageOne = lazy(() => import('./PageOne'));
const PageTwo = lazy(() => import('./PageTwo'));
const PageThree = lazy(() => import('./PageThree'));

const LazyPagerView = () => {
  return (
    <PagerView style={{ flex: 1 }} initialPage={0}>
      <View key="1">
        <Suspense fallback={<Text>Loading Page 1...</Text>}>
          <PageOne />
        </Suspense>
      </View>
      <View key="2">
        <Suspense fallback={<Text>Loading Page 2...</Text>}>
          <PageTwo />
        </Suspense>
      </View>
      <View key="3">
        <Suspense fallback={<Text>Loading Page 3...</Text>}>
          <PageThree />
        </Suspense>
      </View>
    </PagerView>
  );
};

export default LazyPagerView;

Enter fullscreen mode Exit fullscreen mode

3. Conditional Lazy Loading
Most examples show static lazy loading, but what if you need it based on runtime conditions? For instance, in a multi-theme app, you might load components differently based on the selected theme.

Example: Lazy Loading Based on Theme

import React, { lazy, Suspense, useState } from 'react';
import { View, Button, Text } from 'react-native';

// Lazy load components for light and dark themes
const LightThemeComponent = lazy(() => import('./LightThemeComponent'));
const DarkThemeComponent = lazy(() => import('./DarkThemeComponent'));

const App = () => {
  const [theme, setTheme] = useState('light');

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="Toggle Theme" onPress={() => setTheme(theme === 'light' ? 'dark' : 'light')} />
      <Suspense fallback={<Text>Loading theme...</Text>}>
        {theme === 'light' ? <LightThemeComponent /> : <DarkThemeComponent />}
      </Suspense>
    </View>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

4. Lazy Loading with Animations

Lazy loading combined with animations can create visually appealing transitions that make loading less noticeable.

Example: Lazy Loading with a Fade-In Effect

import React, { lazy, Suspense, useRef, useEffect } from 'react';
import { View, Animated, Text } from 'react-native';

const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => {
  const fadeAnim = useRef(new Animated.Value(0)).current; // Initial opacity 0

  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 1000,
      useNativeDriver: true,
    }).start();
  }, []); // Empty dependency array ensures this runs only once

  return (
    <Suspense fallback={<Text>Loading...</Text>}>
      <Animated.View style={{ flex: 1, opacity: fadeAnim }}>
        <LazyComponent />
      </Animated.View>
    </Suspense>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

Real-World Insights and Best Practices

1- Analyze Usage Patterns: Lazy load frequently accessed resources early in idle times (e.g., while the user is reading or interacting with another component).

2- Combine Lazy Loading with Data Fetching: If your component relies on API data, consider triggering both simultaneously.

3- Monitor Performance in Low-End Devices: Always test lazy loading impact on slower devices to ensure improvements.

Top comments (0)