# Hooks API

This section provides a detailed reference for the custom React Hooks available within the library. These hooks are designed to encapsulate and reuse stateful logic, simplifying common tasks and interactions within a Blocklet environment.

## useComponentInstalled

This hook checks whether one or more specified optional components (identified by their DIDs) are installed. It is essential for implementing features that rely on other Blocklets as dependencies. The hook provides the installation status and necessary URLs to prompt the user for installation if required.

### Parameters

The hook accepts a single object with the following properties:

<x-field-group>
  <x-field data-name="did" data-type="string | string[]" data-required="true">
    <x-field-desc markdown>The Decentralized Identifier (DID) or an array of DIDs for the component(s) to check. A single string can contain multiple DIDs separated by `;;`.</x-field-desc>
  </x-field>
  <x-field data-name="onInstalled" data-type="function" data-required="false">
    <x-field-desc markdown>An optional callback function that is triggered when all specified components are already installed.</x-field-desc>
  </x-field>
  <x-field data-name="onError" data-type="function" data-required="false">
    <x-field-desc markdown>An optional callback function that is triggered when one or more specified components are not installed.</x-field-desc>
  </x-field>
</x-field-group>

### Returns

It returns an object containing the installation state and related data:

<x-field-group>
  <x-field data-name="optComponents" data-type="array">
    <x-field-desc markdown>An array of component objects that are not installed. Each object includes metadata such as `meta.did`, `storeUrl`, and `installUrl`.</x-field-desc>
  </x-field>
  <x-field data-name="installed" data-type="boolean">
    <x-field-desc markdown>A boolean value that is `true` if all specified components are installed and defined in the `blocklet.yml`, and `false` otherwise.</x-field-desc>
  </x-field>
  <x-field data-name="installStatus" data-type="object">
    <x-field-desc markdown>An object where keys are component DIDs and values are their current installation status (e.g., 'waiting', 'installing'). This state is updated via `window.postMessage` events.</x-field-desc>
  </x-field>
  <x-field data-name="setInstallStatus" data-type="function">
    <x-field-desc markdown>The state setter function to manually update the `installStatus` object.</x-field-desc>
  </x-field>
  <x-field data-name="definedInBlockletYML" data-type="boolean">
    <x-field-desc markdown>A boolean indicating whether the component is defined in the blocklet's configuration (`blocklet.yml`).</x-field-desc>
  </x-field>
</x-field-group>

### Example Usage

The following example demonstrates how to use `useComponentInstalled` to conditionally render a feature or a `ComponentInstaller` component if a dependency is missing.

```javascript "ComponentFeature.js" icon=logos:javascript
import React from 'react';
import { useComponentInstalled, ComponentInstaller } from '@blocklet/ui-react';

const REQUIRED_DID = 'z8ia24z55nve2TSF5m1aZ5322d9f48a43D4a'; // Example DID

function ComponentFeature() {
  const { installed, optComponents } = useComponentInstalled({ did: REQUIRED_DID });

  if (!installed) {
    // Render the installer UI if the component is not present
    return <ComponentInstaller components={optComponents} />;
  }

  // Render the feature that depends on the installed component
  return (
    <div>
      <h2>My Feature</h2>
      <p>This feature requires the component with DID: {REQUIRED_DID}</p>
      {/* ... feature implementation ... */}
    </div>
  );
}

export default ComponentFeature;
```

## useFollow

This hook manages the following relationship between the currently authenticated user and another user specified by their DID. It handles the API calls for following and unfollowing, and provides the current follow status.

### Parameters

<x-field-group>
  <x-field data-name="userDid" data-type="string" data-required="true">
    <x-field-desc markdown>The DID of the user profile to check the follow status against.</x-field-desc>
  </x-field>
  <x-field data-name="t" data-type="function" data-required="true">
    <x-field-desc markdown>A translation function used for displaying success or error messages (e.g., from `react-i18next`).</x-field-desc>
  </x-field>
  <x-field data-name="isMySelf" data-type="boolean" data-required="true">
    <x-field-desc markdown>A boolean that should be set to `true` if the `userDid` belongs to the currently logged-in user.</x-field-desc>
  </x-field>
</x-field-group>

### Returns

Returns an object with the following properties:

<x-field-group>
  <x-field data-name="followed" data-type="boolean">
    <x-field-desc markdown>Indicates if the current user is following the user specified by `userDid`. `true` if following, `false` otherwise.</x-field-desc>
  </x-field>
  <x-field data-name="followUser" data-type="function">
    <x-field-desc markdown>A stable function to call to follow the user. It handles the API request and updates the `followed` state on success.</x-field-desc>
  </x-field>
  <x-field data-name="unfollowUser" data-type="function">
    <x-field-desc markdown>A stable function to call to unfollow the user. It handles the API request and updates the `followed` state on success.</x-field-desc>
  </x-field>
</x-field-group>

### Example Usage

This example shows how to create a `FollowButton` component that displays a "Follow" or "Unfollow" action based on the relationship status.

```javascript "FollowButton.js" icon=logos:javascript
import React from 'react';
import Button from '@mui/material/Button';
import { useTranslation } from 'react-i18next';
import { useFollow } from '@blocklet/ui-react/hooks';
import { useSession } from '@blocklet/did-connect-react';

function FollowButton({ profileDid }) {
  const { session } = useSession();
  const { t } = useTranslation();
  const isMySelf = session?.user?.did === profileDid;

  const { followed, followUser, unfollowUser } = useFollow({
    userDid: profileDid,
    t,
    isMySelf,
  });

  if (isMySelf) {
    return null; // Do not show button on your own profile
  }

  const handleClick = () => {
    if (followed) {
      unfollowUser();
    } else {
      followUser();
    }
  };

  return (
    <Button variant="contained" onClick={handleClick}>
      {followed ? t('profile.unfollow') : t('profile.follow')}
    </Button>
  );
}

export default FollowButton;
```

## useMobile

A simple utility hook for creating responsive components. It leverages Material-UI's `useMediaQuery` to determine if the current viewport width is below a specified breakpoint.

### Parameters

<x-field-group>
  <x-field data-name="key" data-type="number | Breakpoint" data-default="'sm'" data-required="false">
    <x-field-desc markdown>The Material-UI breakpoint key (e.g., `'xs'`, `'sm'`, `'md'`) or a pixel value to check against. The hook returns `true` if the screen width is smaller than this value.</x-field-desc>
  </x-field>
</x-field-group>

### Returns

Returns a `boolean` value: `true` if the viewport is smaller than the specified breakpoint, `false` otherwise.

### Example Usage

This hook must be used within a component tree that is wrapped by a Material-UI `ThemeProvider`.

```javascript "ResponsiveComponent.js" icon=logos:javascript
import React from 'react';
import Typography from '@mui/material/Typography';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { useMobile } from '@blocklet/ui-react/hooks';

// A component that uses the hook
function ResponsiveComponent() {
  const isMobile = useMobile({ key: 'md' }); // Check against the 'md' breakpoint

  return (
    <div>
      {isMobile ? (
        <Typography variant="h6">Mobile View</Typography>
      ) : (
        <Typography variant="h4">Desktop View</Typography>
      )}
      <p>Resize your browser window to see the content change.</p>
    </div>
  );
}

// The component must be wrapped in a ThemeProvider
const theme = createTheme();

function App() {
  return (
    <ThemeProvider theme={theme}>
      <ResponsiveComponent />
    </ThemeProvider>
  );
}

export default App;
```

---

By using these hooks, you can efficiently implement complex features with minimal boilerplate code. For more information on the components that might use these hooks, please see the [Components](./components.md) documentation.