# React

> @vimine/sdk/react 中的 VimineProvider、useVimine 和 SignInButton。

URL: https://developers.vimine.network/zh-hant/sdk/react/

```jsx
import { VimineProvider, useVimine, SignInButton } from '@vimine/sdk/react';
```

一個 provider：持有**一個** `Vimine` 用戶端，在掛載時處理登入返回，並把工作階段提供給元件樹；一個 hook；一個按鈕。需要 React ≥ 18（可選的 peer dependency：SDK 不會安裝它）。

## 範例

```jsx title="main.jsx"
import { Vimine } from '@vimine/sdk';
import { VimineProvider } from '@vimine/sdk/react';

const vimine = new Vimine({ clientId: 'vmc_…', redirectUri: `${location.origin}/vimine/callback` });

createRoot(document.getElementById('root')).render(
    <VimineProvider client={vimine} onSignedIn={({ returnTo }) => navigate(returnTo || '/')}>
        <App />
    </VimineProvider>
);
```

```jsx title="MembershipCard.jsx"
import { useEffect, useState } from 'react';
import { useVimine, SignInButton } from '@vimine/sdk/react';

export function MembershipCard() {
    const { client, isSignedIn, loading, signOut } = useVimine();
    const [card, setCard] = useState(null);

    useEffect(() => {
        if (isSignedIn) client.membership.get().then(setCard);
    }, [client, isSignedIn]);

    if (loading) return <p>正在登入…</p>;
    if (!isSignedIn) return <SignInButton returnTo={location.pathname}>使用 Vimine 登入</SignInButton>;
    return (
        <>
            <p>會員卡：{card?.verdict === 'valid' ? '有效' : card?.verdict}</p>
            <button onClick={() => signOut()}>登出</button>
        </>
    );
}
```

provider **也**必須掛載在回呼頁面（`redirectUri`）上：它正是在那裡交換授權碼。

## `<VimineProvider>`

| Prop | | |
|---|---|---|
| `client` | `Vimine` | 實例（請在 render 之外建立） |
| `handleRedirect` | `boolean`，預設 `true` | 頁面載入時若帶有登入參數，則交換授權碼 |
| `onSignedIn` | `(result: RedirectResult) => void` | 交換之後呼叫：`result.returnTo` 即傳給 `signIn()` 的值 |
| `onRedirectError` | `(error: VimineError) => void` | `access_denied`、`state_mismatch` 等 |

## `useVimine()`

傳回：

| | |
|---|---|
| `client` | 該 `Vimine` 實例 |
| `session` | 目前工作階段或 `null`，每次登入、重新整理和登出時更新 |
| `isSignedIn` | `!!session` |
| `loading` | 交換返回的授權碼期間為 `true` |
| `signIn(options?)` | 與 `client.signIn` 相同 |
| `signOut(options?)` | 與 `client.signOut` 相同 |

在 provider 之外使用時會拋出錯誤。

## `<SignInButton>`

一個普通的 `<button>`，**由點選**開始登入（登入頁面必須由使用者操作觸發）。接受 `scopes`、`prompt`、`returnTo` 以及任何按鈕屬性；`loading` 期間處於停用狀態。預設文字：“Accedi con Vimine”（義大利語）。
