# useConnect

`useConnect` hook 提供了一种强大的、编程化的方式来打开、关闭和管理 `DidConnect` UI 模态框。当您需要比声明式的 `Button` 组件提供更多对连接流程的控制时，例如从自定义 UI 元素、菜单项或响应应用程序事件来触发模态框，它就是理想的解决方案。

此 hook 是 `Button` 组件背后的引擎，让您可以直接访问相同的核心功能。

## 工作原理

`useConnect` hook 返回两个主要元素：

1.  **`connectHolder`**：一个必须在组件树中渲染的 React 元素。此元素负责在 `DidConnect` 模态框被激活时进行渲染。在 `open` 函数被调用之前，它保持不可见。
2.  **`connectApi`**：一个包含用于控制模态框生命周期的函数（`open`、`close`、`openPopup`、`loginOAuth`）的对象。

<!-- DIAGRAM_IMAGE_START:flowchart:4:3:1765962229 -->
![useConnect](assets/diagram/use-connect-diagram-0.zh.jpg)
<!-- DIAGRAM_IMAGE_END -->

## 设置

要使用此 hook，请在您的组件中导入并调用它。然后，确保在您的应用程序中的某个位置渲染 `connectHolder`，最好是在顶层组件中，以确保模态框可以覆盖所有其他内容。

```javascript Basic Setup icon=logos:javascript
import React from 'react';
import { useConnect } from '@arcblock/did-connect-react';

function MyComponent() {
  // 1. 初始化 hook
  const { connectHolder, connectApi } = useConnect();

  const handleLogin = () => {
    // 2. 使用 API 打开模态框
    connectApi.open({
      action: 'login',
      onSuccess: (result) => {
        console.log('登录成功！', result);
      },
      onClose: () => {
        console.log('模态框被用户关闭。');
      }
    });
  };

  return (
    <div>
      <button type="button" onClick={handleLogin}>
        Login with DID
      </button>

      {/* 3. 渲染 holder 组件 */}
      {connectHolder}
    </div>
  );
}

export default MyComponent;
```

## API 参考

`connectApi` 对象提供了以下方法来控制连接过程。

### `connectApi.open(options)`

这是触发和显示 `DidConnect` 模态框的主要函数。它接受一个 `options` 对象，用于配置连接会话的行为、外观和回调。

**参数 (`options`)**

<x-field-group>
  <x-field data-name="action" data-type="string" data-required="true">
    <x-field-desc markdown>连接请求的目的，例如 `login`、`claim`、`sign` 等。这决定了钱包内的操作流程。</x-field-desc>
  </x-field>
  <x-field data-name="onSuccess" data-type="(result: object) => void" data-required="false">
    <x-field-desc markdown>当用户在钱包中成功完成操作时执行的回调函数。`result` 对象包含来自钱包的响应。</x-field-desc>
  </x-field>
  <x-field data-name="onClose" data-type="() => void" data-required="false">
    <x-field-desc markdown>当用户在未完成操作的情况下手动关闭模态框时执行的回调函数。</x-field-desc>
  </x-field>
  <x-field data-name="onError" data-type="(error: any) => void" data-required="false">
    <x-field-desc markdown>如果在过程中发生错误（例如超时或网络问题）时执行的回调函数。</x-field-desc>
  </x-field>
  <x-field data-name="messages" data-type="ConnectMessages" data-required="false">
    <x-field-desc markdown>一个用于自定义模态框中显示文本的对象。有关详细信息，请参阅 `ConnectMessages` 类型。</x-field-desc>
    <x-field data-name="title" data-type="string" data-desc="模态框标题。"></x-field>
    <x-field data-name="scan" data-type="string" data-desc="二维码附带的文本。"></x-field>
    <x-field data-name="confirm" data-type="string" data-desc="确认步骤的文本。"></x-field>
    <x-field data-name="success" data-type="ReactNode" data-desc="成功屏幕的内容。"></x-field>
  </x-field>
  <x-field data-name="popup" data-type="boolean" data-default="true">
    <x-field-desc markdown>如果为 `true`，UI 将作为模态对话框显示。如果为 `false`，它将内联渲染，需要设置 `containerEl`。</x-field-desc>
  </x-field>
  <x-field data-name="containerEl" data-type="Element" data-required="false">
    <x-field-desc markdown>当 `popup` 设置为 `false` 时，`DidConnect` 组件将在此 DOM 元素中渲染。</x-field-desc>
  </x-field>
  <x-field data-name="closeTimeout" data-type="number" data-default="2000">
    <x-field-desc markdown>成功连接后，模态框自动关闭前的延迟时间（以毫秒为单位）。</x-field-desc>
  </x-field>
  <x-field data-name="checkInterval" data-type="number" data-default="2000">
    <x-field-desc markdown>轮询服务器以检查会话状态的间隔时间（以毫秒为单位）。</x-field-desc>
  </x-field>
  <x-field data-name="checkTimeout" data-type="number" data-default="300000">
    <x-field-desc markdown>连接尝试超时的总时间（以毫秒为单位）。</x-field-desc>
  </x-field>
  <x-field data-name="extraParams" data-type="object" data-default="{}">
    <x-field-desc markdown>要包含在会话创建请求中的任何额外参数，这些参数可以在服务器端检索。</x-field-desc>
  </x-field>
</x-field-group>

### `connectApi.close()`

手动关闭 `DidConnect` 模态框。模态框在成功或用户取消时会自动关闭，但如果需要因其他原因以编程方式关闭它，可以调用此函数。

```javascript icon=lucide:x-circle
// 示例：在成功回调中短暂延迟后关闭模态框
connectApi.open({
  action: 'login',
  onSuccess: () => {
    showTemporarySuccessMessage();
    setTimeout(() => {
      connectApi.close();
    }, 1500);
  },
  closeTimeout: 999999 // 防止自动关闭
});
```

### `connectApi.openPopup(params, options)`

此函数提供了一种替代的连接方法，它会在新的浏览器弹出窗口中打开 DID Connect 流程，而不是在当前页面内打开模态框。这对于某些类似 OAuth 的流程或在无法注入模态框的网站上进行集成时非常有用。

**参数**

<x-field-group>
  <x-field data-name="params" data-type="ConnectProps" data-required="true">
    <x-field-desc markdown>与 `open` 方法的选项类似。一个关键区别是，`params.extraParams.provider` 是**必需的**，用于标识认证方法（例如 'github'、'google'）。</x-field-desc>
  </x-field>
  <x-field data-name="options" data-type="object" data-required="false">
    <x-field-desc markdown>弹出窗口本身的配置。</x-field-desc>
    <x-field data-name="baseUrl" data-type="string" data-desc="用于构建弹出窗口 URL 的基础 URL。"></x-field>
    <x-field data-name="locale" data-type="string" data-default="en" data-desc="弹出窗口内容的区域设置。"></x-field>
    <x-field data-name="popupOptions" data-type="object" data-desc="直接传递给 `window.open()` 的选项，用于自定义弹出窗口的大小和功能。"></x-field>
  </x-field>
</x-field-group>

**用法**

`openPopup` 函数返回一个 `Promise`，它在成功时解析为认证数据，在失败或取消时拒绝。

```javascript icon=lucide:external-link
const handleGithubLogin = async () => {
  try {
    const result = await connectApi.openPopup({
      action: 'login',
      onSuccess: () => console.log('此回调也会被触发'),
      extraParams: { provider: 'github' } // 这是必需的
    });
    console.log('通过弹出窗口登录成功：', result);
  } catch (err) {
    if (err.message === 'Popup closed') {
      console.log('用户关闭了弹出窗口。');
    } else {
      console.error('发生错误：', err);
    }
  }
};
```

### `connectApi.loginOAuth(options)`

这是一个辅助函数，用于直接启动 OAuth 登录流程。它是一个较低级别的实用工具，在库的其他部分内部使用。

**参数 (`options`)**

<x-field-group>
  <x-field data-name="provider" data-type="string" data-required="true" data-desc="要使用的 OAuth 提供商，例如 'github'、'google'。"></x-field>
  <x-field data-name="action" data-type="string" data-required="true" data-desc="操作，通常是 'login'。"></x-field>
  <x-field data-name="extraParams" data-type="object" data-required="false" data-desc="OAuth 流程的附加参数。"></x-field>
  <x-field data-name="onLogin" data-type="function" data-required="true" data-desc="成功登录后执行的回调函数。"></x-field>
</x-field-group>