Lesson 40 of 60 – useEffect Hook in React Native
67%

useEffect Hook in React Native

The useEffect Hook is used to perform side effects in a functional component. Side effects are operations that happen outside the normal process of calculating and displaying the component UI.

Common examples include loading data, setting up timers, subscribing to events, updating external systems and performing cleanup when a component is no longer being used.

Note: The useEffect Hook is imported from React and is normally used inside functional components.

1. What is useEffect?

useEffect is a React Hook that lets a functional component perform side effects after rendering.

import {
    useEffect
} from 'react';

It is commonly used when a component needs to interact with something outside its immediate rendering logic.

2. What are Side Effects?

A side effect is an operation that interacts with something outside the component's returned UI.

Examples include:

  • Fetching data from an API.
  • Starting a timer.
  • Listening for events.
  • Updating an external system.
  • Reading information from storage.
  • Cleaning up subscriptions.

3. Importing useEffect

Import useEffect from React.

import React, {
    useEffect
} from 'react';

If you also need state, you can import both Hooks together.

import React, {
    useState,
    useEffect
} from 'react';

4. Basic useEffect Syntax

useEffect(() => {

    // Side effect

}, []);

The first argument is the effect function. The second argument is the dependency array.

5. useEffect Without Dependencies

useEffect(() => {

    console.log(
        'Effect executed'
    );

});

When no dependency array is provided, the effect runs after each completed render.

This behavior should be used carefully because an effect can run very frequently when the component renders often.

6. useEffect with Empty Dependency Array

useEffect(() => {

    console.log(
        'Component effect'
    );

}, []);

An empty dependency array means the effect does not depend on changing values from the component. It runs after the initial mount.

7. useEffect with a Dependency

useEffect(() => {

    console.log(
        'Count changed:',
        count
    );

}, [count]);

The effect runs after the initial render and when count changes.

8. useEffect with Multiple Dependencies

useEffect(() => {

    console.log(
        name,
        age
    );

}, [name, age]);

The effect reacts when either name or age changes.

9. useEffect with useState

const [count, setCount] =
    useState(0);

useEffect(() => {

    console.log(
        'Count:',
        count
    );

}, [count]);

This is a common pattern when an effect needs to respond to state changes.

10. Running an Effect When a Value Changes

const [name, setName] =
    useState('');

useEffect(() => {

    console.log(
        'Name changed:',
        name
    );

}, [name]);

Whenever name changes, the effect runs after rendering.

11. useEffect for API Requests

One common use of useEffect is loading data when a screen starts.

useEffect(() => {

    fetchData();

}, []);

The fetchData function can perform the required data request.

12. Creating a Data Loading Function

const fetchData = async () => {

    try {

        const response =
            await fetch(
                'https://example.com/api/students'
            );

        const data =
            await response.json();

        console.log(data);

    } catch (error) {

        console.log(error);

    }

};

The effect can call this function when the component needs to load data.

13. useEffect with API Data and State

const [students, setStudents] =
    useState([]);

useEffect(() => {

    const loadStudents = async () => {

        const response =
            await fetch(
                'https://example.com/api/students'
            );

        const data =
            await response.json();

        setStudents(data);

    };

    loadStudents();

}, []);

The fetched data can be stored in state and displayed in the UI.

14. useEffect with Loading State

const [loading, setLoading] =
    useState(true);

useEffect(() => {

    const loadData = async () => {

        try {

            // Load data here

        } finally {

            setLoading(false);

        }

    };

    loadData();

}, []);

A loading state can be used to display an ActivityIndicator while data is being loaded.

15. useEffect with Timer

An effect can be used to start a timer.

useEffect(() => {

    const timer =
        setTimeout(() => {

            console.log(
                'Timer finished'
            );

        }, 3000);

}, []);

The timer starts when the effect runs.

16. Cleaning Up a Timer

Timers should be cleaned up when necessary.

useEffect(() => {

    const timer =
        setTimeout(() => {

            console.log(
                'Timer finished'
            );

        }, 3000);

    return () => {

        clearTimeout(timer);

    };

}, []);

The function returned by the effect is called the cleanup function.

17. Cleanup Function

An effect can return a cleanup function.

useEffect(() => {

    // Setup

    return () => {

        // Cleanup

    };

}, []);

Cleanup is useful when an effect creates a subscription, timer, listener or another resource that needs to be released.

18. useEffect with setInterval

useEffect(() => {

    const interval =
        setInterval(() => {

            console.log(
                'Running...'
            );

        }, 1000);

    return () => {

        clearInterval(interval);

    };

}, []);

The cleanup function stops the interval.

19. useEffect for Event Listeners

Effects can be used to register event listeners and remove them during cleanup.

useEffect(() => {

    const handleEvent = () => {

        console.log(
            'Event received'
        );

    };

    // Add listener here

    return () => {

        // Remove listener here

    };

}, []);

20. useEffect for External Synchronization

An effect can be useful when the component needs to synchronize with something outside React.

Examples include:

  • External services.
  • Timers.
  • Subscriptions.
  • Storage systems.
  • Native APIs.
  • Other external resources.

21. Understanding the Dependency Array

The dependency array tells React which values are used by the effect and when the effect should be synchronized again.

useEffect(() => {

    console.log(name);

}, [name]);

Here, name is a dependency of the effect.

22. Dependency Array Examples

No dependency array:

useEffect(() => {

    // Runs after renders

});

Empty dependency array:

useEffect(() => {

    // Runs after initial mount

}, []);

Dependency:

useEffect(() => {

    // Runs after initial mount
    // and when count changes

}, [count]);

23. useEffect and Form Input

An effect can respond to a form value changing.

const [email, setEmail] =
    useState('');

useEffect(() => {

    console.log(
        'Email changed:',
        email
    );

}, [email]);

This can be useful for specific synchronization or derived external actions, although simple calculations are often better performed directly during rendering.

24. useEffect and FlatList Data

const [students, setStudents] =
    useState([]);

useEffect(() => {

    const loadStudents = async () => {

        const response =
            await fetch(
                'https://example.com/api/students'
            );

        const data =
            await response.json();

        setStudents(data);

    };

    loadStudents();

}, []);

The resulting state can then be provided to a FlatList.

25. Avoiding Unnecessary Effects

Not every calculation needs useEffect.

For example, if a value can be calculated directly from existing state or props, it may not need an effect.

const fullName =
    firstName + ' ' + lastName;

Using an effect for every simple calculation can make component logic more complicated than necessary.

26. Common useEffect Mistakes

  • Forgetting required dependencies.
  • Creating an effect for a simple calculation.
  • Starting a timer without cleaning it up.
  • Creating subscriptions without removing them.
  • Causing repeated effects unintentionally.
  • Putting too much unrelated logic into one effect.
  • Ignoring loading and error states for asynchronous work.
  • Updating state in an effect without understanding its dependencies.

27. Complete API Loading Example

import React, {
    useEffect,
    useState
} from 'react';

import {
    View,
    Text,
    FlatList,
    ActivityIndicator,
    StyleSheet
} from 'react-native';

export default function App() {

    const [students, setStudents] =
        useState([]);

    const [loading, setLoading] =
        useState(true);

    const [error, setError] =
        useState('');

    useEffect(() => {

        const loadStudents = async () => {

            try {

                setLoading(true);
                setError('');

                const response =
                    await fetch(
                        'https://example.com/api/students'
                    );

                if (!response.ok) {

                    throw new Error(
                        'Request failed'
                    );

                }

                const data =
                    await response.json();

                setStudents(data);

            } catch (error) {

                setError(
                    'Unable to load students'
                );

            } finally {

                setLoading(false);

            }

        };

        loadStudents();

    }, []);

    if (loading) {

        return (

            <View
                style={styles.center}
            >

                <ActivityIndicator
                    size="large"
                />

                <Text>
                    Loading...
                </Text>

            </View>

        );

    }

    if (error !== '') {

        return (

            <View
                style={styles.center}
            >

                <Text>
                    {error}
                </Text>

            </View>

        );

    }

    return (

        <View style={styles.container}>

            <Text style={styles.title}>
                Students
            </Text>

            <FlatList
                data={students}
                keyExtractor={
                    item => item.id.toString()
                }
                renderItem={({
                    item
                }) => (

                    <View
                        style={styles.item}
                    >

                        <Text>
                            {item.name}
                        </Text>

                    </View>

                )}
            />

        </View>

    );

}

const styles = StyleSheet.create({

    container: {
        flex: 1,
        padding: 20
    },

    center: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    },

    title: {
        fontSize: 28,
        fontWeight: 'bold',
        marginBottom: 20
    },

    item: {
        padding: 15,
        borderWidth: 1,
        borderColor: '#CBD5E1',
        borderRadius: 8,
        marginBottom: 10
    }

});

28. useEffect Best Practices

  • Use effects for actual side effects.
  • Keep each effect focused on a related task.
  • Declare appropriate dependencies.
  • Clean up timers and subscriptions when necessary.
  • Handle loading and error states for asynchronous operations.
  • Avoid unnecessary effects.
  • Keep API loading logic organized.
  • Do not use effects as a replacement for ordinary calculations.
  • Keep effect logic readable and maintainable.

29. Common useEffect Uses

Use Case Purpose
API Requests Load data from a backend
Timers Start and clean up timers
Subscriptions Subscribe and unsubscribe from external sources
Event Listeners Register and remove listeners
External Synchronization Synchronize with external systems
Storage Read or synchronize external stored data when appropriate
State Changes React to particular state changes when an external side effect is required

30. Complete useEffect Workflow

Identify Side Effect
        ↓
Import useEffect
        ↓
Create Effect Function
        ↓
Add Required Dependencies
        ↓
Perform Side Effect
        ↓
Update State if Required
        ↓
React Re-renders
        ↓
Effect Runs When Dependencies Require It
        ↓
Clean Up Resources When Necessary
        ↓
Keep Effect Logic Organized

The useEffect Hook is important for handling side effects in React Native applications. It is commonly used with API requests, timers, subscriptions, event listeners and other external operations.

📌 Key Points

  • useEffect is used for side effects.
  • It is commonly used inside functional components.
  • The dependency array controls when the effect is synchronized again.
  • An empty dependency array is commonly used for effects that do not depend on changing component values.
  • Dependencies should reflect the values used by the effect.
  • API requests are a common use case.
  • Timers and subscriptions may require cleanup.
  • The cleanup function is returned from the effect.
  • Not every calculation requires an effect.
  • Good effect organization makes React Native applications easier to maintain.

🧠 Quick Quiz

Question: What is the main purpose of the useEffect Hook?