Skip to content

07 RN - UseEffect

useEffect

  • The Effect Hook, useEffect, adds the ability to perform side effects from a function component.
  • It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes. useEffect runs after every render.

useEffect - no cleanup

useEffect runs after every render. Has access to state/prop variables.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import React, { useState, useEffect } from 'react';

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

    useEffect(() => {
        document.title = `You clicked ${count} times`;
    });

    return (
        <>
            <h1>Home {count}</h1>
            <button onClick={() => setCount(count + 1)}>Add 1</button>
        </>
    );
}

export default Home;

useEffect – cleanup

1
useEffect(effect: React.EffectCallback, deps?: React.DependencyList | undefined): void
  • If you need to call some function to clean up – return the callback function from the useEffect().
  • Same code that sould run from componentWillUnmount() class lifecycle method.


  • useEffect can be used several times – split unrelated logic.
  • NB! – pass second parameter – array of variables that are used in effect logic – to let React decide should useEffect run. If values are same between renders - effect will not run.
1
2
3
4
5
6
useEffect(() => { 
    API.subscribe();
    return function cleanup() { 
        API.unsubscribe() 
    } 
})

Returned function will run after previous render.

useEffect - cleanup - Axios example

  • Do not update component when it is unloaded
  • Cancel Axios request
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function Example(props) {
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        let mounted = true;

        fetchAPI.then(() => {
            if (mounted) {
                setLoading(false);
            }
        })

        return function cleanup() {
            mounted = false;
        }
    }, [])

    return <div>{loading ? <p>loading...</p> : <p>loaded</p>}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
useEffect(() => {
    const source = axios.CancelToken.source();

    const fetchUsers = async () => {
        try {
            await Axios.get('/users', {
                cancelToken: source.token
            })
            // ...
        } catch (error) {
            if (Axios.isCancel(error)) {

            } else {
                throw error;
            }
        }
    }

    fetchUsers();

    return () => {
        source.cancel();
    }
}, [])

Axios based example - func, hooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const GpsSessions = () => {
    const [items, setItems] = useState([] as IGpsSession[]);

    useEffect(() => {
        const fetchData = async () => setItems(await GpsSessionsApi.getAll());
        fetchData();
    });

    return (
        <>
            <h1>Gps Sessions</h1>
            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Name</th>
                        <th>Description</th>
                        <th>Recorded At</th>
                        <th>Locations</th>
                        <th>User</th>
                    </tr>
                </thead>
                <tbody>
                    {items.map(gpsSession => <RowDisplay gpsSession={gpsSession} />)}
                </tbody>
            </table>
        </>
    );
}

export default GpsSessions;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import React, { useState, useEffect } from 'react';
import { IGpsSession } from '../domain/IGpsSession';
import { GpsSessionsApi } from '../services/GpsSessionApi';

const RowDisplay = (props: { gpsSession: IGpsSession }) => (
    <tr key={props.gpsSession.id}>
        <td>{props.gpsSession.id}</td>
        <td>{props.gpsSession.name}</td>
        <td>{props.gpsSession.description}</td>
        <td>{props.gpsSession.recordedAt}</td>
        <td>{props.gpsSession.gpsLocationsCount}</td>
        <td>{props.gpsSession.userFirstLastName}</td>
    </tr>
)

useMemo

The useMemo hook is used to optimize the performance of react component by memoizing (caching) the result of function. Useful in cases when function is expensive. Recalculation is triggered when dependencies are changed.

1
2
3
const sum = useMemo(() => {
    return ...some_expensive_calc_with_numbers...
}, [numbers]);

useCallback

Similar to useMemo, but returns callback function - updated when dependencies are changed. Avoids needless updates.