JAVASCRIPT

Handle Asynchronous Operations with a Custom useAsync Hook

Create a versatile custom React hook to manage the state of any asynchronous operation, centralizing loading, error, and data states for cleaner and more robust component logic.

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

// Custom Hook: useAsync
const useAsync = (asyncFunction, immediate = true) => {
  const [status, setStatus] = useState('idle'); // 'idle', 'pending', 'success', 'error'
  const [value, setValue] = useState(null);
  const [error, setError] = useState(null);

  // The execute function calls the async function and sets the state
  const execute = React.useCallback(() => {
    setStatus('pending');
    setValue(null);
    setError(null);
    return asyncFunction()
      .then((response) => {
        setValue(response);
        setStatus('success');
      })
      .catch((error) => {
        setError(error);
        setStatus('error');
      });
  }, [asyncFunction]); // Recreate if asyncFunction changes

  // Call execute if we want to fire it right away
  useEffect(() => {
    if (immediate) {
      execute();
    }
  }, [execute, immediate]);

  return { execute, status, value, error };
};

// Example Usage:
const fetchUserData = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) {
        resolve({ name: 'John Doe', email: '[email protected]' });
      } else {
        reject(new Error('Failed to fetch user data!'));
      }
    }, 1500);
  });

const UserProfile = () => {
  const { execute, status, value, error } = useAsync(fetchUserData, false); // Not immediate

  return (
    <div>
      <h1>User Profile</h1>
      {status === 'idle' && <button onClick={execute}>Load User Data</button>}
      {status === 'pending' && <p>Loading user data...</p>}
      {status === 'error' && <p style={{ color: 'red' }}>Error: {error?.message}</p>}
      {status === 'success' && value && (
        <div>
          <p>Name: {value.name}</p>
          <p>Email: {value.email}</p>
        </div>
      )}
      {status !== 'pending' && status !== 'idle' && (
          <button onClick={execute}>Reload User Data</button>
      )}
    </div>
  );
};

const App = () => <UserProfile />;
How it works: The `useAsync` hook provides a structured way to handle asynchronous operations (like API calls) within React components. It manages `status` (`idle`, `pending`, `success`, `error`), `value` (the data returned), and `error` states. The `execute` function runs the provided `asyncFunction`. This centralizes common async logic, making components cleaner by abstracting away the boilerplate for loading, error, and data states. The `immediate` flag allows control over whether the function runs on mount or needs to be triggered manually.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs