DEV Community

Cover image for React Custom Hook: useAsync
Sergey Leschev
Sergey Leschev

Posted on

8 1 1 1 2

React Custom Hook: useAsync

In this article series, we embark on a journey through the realm of custom React hooks, discovering their immense potential for elevating your development projects. Our focus today is on the "useAsync" hook, one of the many carefully crafted hooks available in the collection of React custom hooks.

Github: https://github.com/sergeyleschev/react-custom-hooks

import { useCallback, useEffect, useState } from "react"

export default function useAsync(callback, dependencies = []) {
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState()
    const [value, setValue] = useState()

    const callbackMemoized = useCallback(() => {
        setLoading(true)
        setError(undefined)
        setValue(undefined)
        callback()
            .then(setValue)
            .catch(setError)
            .finally(() => setLoading(false))
    }, dependencies)

    useEffect(() => {
        callbackMemoized()
    }, [callbackMemoized])

    return { loading, error, value }
}
Enter fullscreen mode Exit fullscreen mode

The useAsync hook takes in a callback function that performs the asynchronous operation and an optional array of dependencies. It returns an object with three properties: loading, error, and value. The loading property indicates whether the operation is currently in progress, while the error property holds any error messages encountered during the process. Finally, the value property contains the resolved value of the asynchronous operation.

One of the significant advantages of useAsync is its ability to memoize the callback function using useCallback. This ensures that the callback is only recreated when the dependencies change, preventing unnecessary re-renders and optimizing performance. Additionally, the hook employs the useState and useEffect hooks to manage the loading state and invoke the memoized callback function when necessary.

UseAsync can be employed in a wide range of scenarios. Whether you're fetching data from an API, performing computations, or handling form submissions, this custom hook simplifies the management of asynchronous operations throughout your React components. Its flexibility and ease of use make it a valuable addition to any React project.

import useAsync from "./useAsync"

export default function AsyncComponent() {
    const { loading, error, value } = useAsync(() => {
        return new Promise((resolve, reject) => {
            const success = false
            setTimeout(() => {
                success ? resolve("Hi") : reject("Error")
            }, 1000)
        })
    })

    return (
        <div>
            <div>Loading: {loading.toString()}</div>
            <div>{error}</div>
            <div>{value}</div>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

By utilizing useAsync, you can streamline your codebase, enhance reusability, and maintain a consistent and reliable user experience. Give it a try in your next React project and witness the power of simplified asynchronous operations.

Full Version | React Custom Hooks:
https://dev.to/sergeyleschev/supercharge-your-react-projects-with-custom-hooks-pl4

Top comments (1)

Collapse
 
sergeyleschev profile image
Sergey Leschev • Edited

You're absolutely right about the potential double triggering in development due to React's behavior. It's essential to be aware of these aspects and handle side effects appropriately, like using cleanup functions for managing resources.

Your suggestion to explore @tanstack/react-query is valuable. Libraries like React Query can offer more comprehensive solutions and address various considerations that arise when dealing with asynchronous operations.

Thanks for the thoughtful input and the cheerful recommendation! 🌟

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay