Skip to main content

Introduction

Proton WebClients provides a comprehensive collection of React hooks that handle common patterns across the application suite. These hooks are designed to be composable, type-safe, and efficient.

Hook Categories

State Management Hooks

Hooks for managing component state with advanced patterns:

Data Fetching Hooks

Hooks for API interactions and data fetching:

Lifecycle Hooks

Hooks for component lifecycle management:

Utility Hooks

Hooks for common React patterns:

Package Structure

Hooks are organized into two main packages:
packages/hooks/          # Core React hooks
packages/components/hooks/ # Application-specific hooks

Usage Example

import { useLoading } from '@proton/hooks';
import { useApi } from '@proton/components';

function MyComponent() {
  const [loading, withLoading] = useLoading();
  const api = useApi();

  const handleAction = async () => {
    await withLoading(async () => {
      await api({ url: '/api/endpoint', method: 'post' });
    });
  };

  return (
    <button onClick={handleAction} disabled={loading}>
      {loading ? 'Loading...' : 'Submit'}
    </button>
  );
}

TypeScript Support

All hooks are fully typed with TypeScript and provide excellent type inference:
import { useLoading } from '@proton/hooks';

// Return type is automatically inferred
const [loading, withLoading] = useLoading();

// Generic types are supported
interface User { id: string; name: string; }
const result = await withLoading<User>(
  () => fetchUser()
);

Best Practices

1. Use the Right Hook for the Job

Choose hooks that match your specific use case:
  • Use useLoading for single operations
  • Use useLoadingByKey when tracking multiple concurrent operations
  • Use useApiResult for data fetching with automatic loading states

2. Handle Cleanup Properly

Many hooks handle cleanup automatically, but be aware of unmount scenarios:
const [loading, withLoading] = useLoading();

useEffect(() => {
  // withLoading handles cleanup if component unmounts
  withLoading(fetchData());
}, []);

3. Combine Hooks Effectively

const isMounted = useIsMounted();
const [loading, withLoading] = useLoading();

const handleAction = async () => {
  await withLoading(async () => {
    const result = await fetchData();
    if (isMounted()) {
      // Only update state if still mounted
      setState(result);
    }
  });
};

Next Steps

Build docs developers (and LLMs) love