633 lines
13 KiB
Markdown
633 lines
13 KiB
Markdown
|
|
# 🦟 蚊子项目 - React组件库
|
|||
|
|
|
|||
|
|
这是蚊子项目的React组件库,提供完整的分享功能集成。
|
|||
|
|
|
|||
|
|
## 📦 安装
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
npm install @mosquito/react
|
|||
|
|
# 或
|
|||
|
|
yarn add @mosquito/react
|
|||
|
|
# 或
|
|||
|
|
pnpm add @mosquito/react
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🚀 快速开始
|
|||
|
|
|
|||
|
|
### 基础配置
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// src/index.tsx
|
|||
|
|
import React from 'react'
|
|||
|
|
import ReactDOM from 'react-dom/client'
|
|||
|
|
import App from './App'
|
|||
|
|
import { MosquitoProvider } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
const root = ReactDOM.createRoot(document.getElementById('root')!)
|
|||
|
|
root.render(
|
|||
|
|
<React.StrictMode>
|
|||
|
|
<MosquitoProvider
|
|||
|
|
baseUrl="https://api.your-domain.com"
|
|||
|
|
apiKey="your-api-key"
|
|||
|
|
timeout={10000}
|
|||
|
|
>
|
|||
|
|
<App />
|
|||
|
|
</MosquitoProvider>
|
|||
|
|
</React.StrictMode>
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📖 组件文档
|
|||
|
|
|
|||
|
|
### MosquitoShareButton
|
|||
|
|
|
|||
|
|
分享按钮组件,支持一键复制链接到剪贴板。
|
|||
|
|
|
|||
|
|
#### Props
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 默认值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| activityId | `number` | - | 活动ID(必需) |
|
|||
|
|
| userId | `number` | - | 用户ID(必需) |
|
|||
|
|
| template | `string` | 'default' | 分享模板 |
|
|||
|
|
| text | `string` | '分享给好友' | 按钮文字 |
|
|||
|
|
| variant | `'primary'\|'secondary'\|'success'\|'danger'` | 'primary' | 按钮样式 |
|
|||
|
|
| size | `'sm'\|'md'\|'lg'` | 'md' | 按钮大小 |
|
|||
|
|
| disabled | `boolean` | false | 是否禁用 |
|
|||
|
|
|
|||
|
|
#### Events
|
|||
|
|
|
|||
|
|
| 事件 | 参数 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| onCopy | - | 链接已复制到剪贴板 |
|
|||
|
|
| onError | `Error` | 获取分享链接失败 |
|
|||
|
|
|
|||
|
|
#### 示例
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
import { MosquitoShareButton } from '@mosquito/react'
|
|||
|
|
import { useState } from 'react'
|
|||
|
|
|
|||
|
|
function SharePage() {
|
|||
|
|
const activityId = 1
|
|||
|
|
const userId = 100
|
|||
|
|
const [message, setMessage] = useState('')
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<MosquitoShareButton
|
|||
|
|
activityId={activityId}
|
|||
|
|
userId={userId}
|
|||
|
|
template="default"
|
|||
|
|
text="立即分享"
|
|||
|
|
variant="primary"
|
|||
|
|
size="lg"
|
|||
|
|
onCopy={() => setMessage('分享链接已复制到剪贴板')}
|
|||
|
|
onError={(error) => setMessage(`错误: ${error.message}`)}
|
|||
|
|
/>
|
|||
|
|
{message && <p>{message}</p>}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### MosquitoPosterCard
|
|||
|
|
|
|||
|
|
海报展示组件,支持加载状态和错误处理。
|
|||
|
|
|
|||
|
|
#### Props
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 默认值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| activityId | `number` | - | 活动ID(必需) |
|
|||
|
|
| userId | `number` | - | 用户ID(必需) |
|
|||
|
|
| template | `string` | 'default' | 海报模板 |
|
|||
|
|
| width | `string` | '300px' | 宽度 |
|
|||
|
|
| height | `string` | '400px' | 高度 |
|
|||
|
|
| lazy | `boolean` | false | 是否懒加载 |
|
|||
|
|
|
|||
|
|
#### Events
|
|||
|
|
|
|||
|
|
| 事件 | 参数 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| onLoad | - | 海报加载完成 |
|
|||
|
|
| onError | `Error` | 海报加载失败 |
|
|||
|
|
| onClick | - | 海报被点击 |
|
|||
|
|
|
|||
|
|
#### 示例
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
import { MosquitoPosterCard } from '@mosquito/react'
|
|||
|
|
import { useState } from 'react'
|
|||
|
|
|
|||
|
|
function PosterPage() {
|
|||
|
|
const activityId = 1
|
|||
|
|
const userId = 100
|
|||
|
|
const [loading, setLoading] = useState(true)
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<MosquitoPosterCard
|
|||
|
|
activityId={activityId}
|
|||
|
|
userId={userId}
|
|||
|
|
template="premium"
|
|||
|
|
width="350px"
|
|||
|
|
height="500px"
|
|||
|
|
lazy
|
|||
|
|
onLoad={() => setLoading(false)}
|
|||
|
|
onError={(error) => console.error('海报加载失败:', error)}
|
|||
|
|
onClick={() => console.log('海报被点击')}
|
|||
|
|
/>
|
|||
|
|
{loading && <p>加载中...</p>}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### MosquitoLeaderboard
|
|||
|
|
|
|||
|
|
排行榜组件,支持分页和排序。
|
|||
|
|
|
|||
|
|
#### Props
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 默认值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| activityId | `number` | - | 活动ID(必需) |
|
|||
|
|
| page | `number` | 0 | 页码 |
|
|||
|
|
| pageSize | `number` | 20 | 每页大小 |
|
|||
|
|
| topN | `number` | undefined | 只显示前N名 |
|
|||
|
|
| currentUserId | `number` | undefined | 当前用户ID |
|
|||
|
|
| sortable | `boolean` | false | 是否支持排序 |
|
|||
|
|
| exportable | `boolean` | false | 是否显示导出按钮 |
|
|||
|
|
|
|||
|
|
#### Events
|
|||
|
|
|
|||
|
|
| 事件 | 参数 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| onLoad | `entries[]` | 排行榜数据加载完成 |
|
|||
|
|
| onError | `Error` | 排行榜加载失败 |
|
|||
|
|
| onPageChange | `number` | 页码变化 |
|
|||
|
|
| onExport | - | 导出排行榜 |
|
|||
|
|
|
|||
|
|
#### 示例
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
import { MosquitoLeaderboard } from '@mosquito/react'
|
|||
|
|
import { useState } from 'react'
|
|||
|
|
|
|||
|
|
function LeaderboardPage() {
|
|||
|
|
const activityId = 1
|
|||
|
|
const [page, setPage] = useState(0)
|
|||
|
|
const currentUserId = 100
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<MosquitoLeaderboard
|
|||
|
|
activityId={activityId}
|
|||
|
|
page={page}
|
|||
|
|
pageSize={20}
|
|||
|
|
topN={10}
|
|||
|
|
currentUserId={currentUserId}
|
|||
|
|
sortable
|
|||
|
|
exportable
|
|||
|
|
onLoad={(entries) => console.log('加载完成:', entries)}
|
|||
|
|
onError={(error) => console.error('加载失败:', error)}
|
|||
|
|
onPageChange={(newPage) => setPage(newPage)}
|
|||
|
|
onExport={() => console.log('导出排行榜')}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### MosquitoShareModal
|
|||
|
|
|
|||
|
|
分享弹窗组件,提供多种分享方式。
|
|||
|
|
|
|||
|
|
#### Props
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 默认值 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| activityId | `number` | - | 活动ID(必需) |
|
|||
|
|
| userId | `number` | - | 用户ID(必需) |
|
|||
|
|
| open | `boolean` | - | 是否打开 |
|
|||
|
|
| onClose | `() => void` | - | 关闭回调 |
|
|||
|
|
| title | `string` | '分享活动' | 弹窗标题 |
|
|||
|
|
|
|||
|
|
#### 示例
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
import { MosquitoShareModal } from '@mosquito/react'
|
|||
|
|
import { useState } from 'react'
|
|||
|
|
|
|||
|
|
function ShareModalPage() {
|
|||
|
|
const activityId = 1
|
|||
|
|
const userId = 100
|
|||
|
|
const [open, setOpen] = useState(false)
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<button onClick={() => setOpen(true)}>打开分享弹窗</button>
|
|||
|
|
|
|||
|
|
<MosquitoShareModal
|
|||
|
|
activityId={activityId}
|
|||
|
|
userId={userId}
|
|||
|
|
open={open}
|
|||
|
|
onClose={() => setOpen(false)}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔧 Hooks
|
|||
|
|
|
|||
|
|
### useMosquito
|
|||
|
|
|
|||
|
|
核心Hook,提供API调用功能。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { useMosquito } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
function MyComponent() {
|
|||
|
|
const {
|
|||
|
|
// 活动管理
|
|||
|
|
getActivity,
|
|||
|
|
createActivity,
|
|||
|
|
|
|||
|
|
// 分享功能
|
|||
|
|
getShareUrl,
|
|||
|
|
getShareMeta,
|
|||
|
|
|
|||
|
|
// 海报功能
|
|||
|
|
getPosterImage,
|
|||
|
|
getPosterHtml,
|
|||
|
|
|
|||
|
|
// 排行榜
|
|||
|
|
getLeaderboard,
|
|||
|
|
exportLeaderboard,
|
|||
|
|
|
|||
|
|
// 状态
|
|||
|
|
loading,
|
|||
|
|
error,
|
|||
|
|
|
|||
|
|
// 配置
|
|||
|
|
config
|
|||
|
|
} = useMosquito()
|
|||
|
|
|
|||
|
|
const handleGetShareUrl = async () => {
|
|||
|
|
try {
|
|||
|
|
const url = await getShareUrl(1, 100)
|
|||
|
|
console.log('分享链接:', url)
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('获取分享链接失败:', err)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<button onClick={handleGetShareUrl}>
|
|||
|
|
获取分享链接
|
|||
|
|
</button>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### useShareUrl
|
|||
|
|
|
|||
|
|
获取分享链接的专用Hook。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { useShareUrl } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
function ShareUrlComponent({ activityId, userId }: { activityId: number; userId: number }) {
|
|||
|
|
const { shareUrl, loading, error, fetchShareUrl } = useShareUrl(activityId, userId)
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
{loading && <p>加载中...</p>}
|
|||
|
|
{error && <p>错误: {error.message}</p>}
|
|||
|
|
{shareUrl && (
|
|||
|
|
<div>
|
|||
|
|
<p>分享链接: {shareUrl}</p>
|
|||
|
|
<button onClick={() => fetchShareUrl()}>刷新</button>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### usePoster
|
|||
|
|
|
|||
|
|
海报功能的专用Hook。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { usePoster } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
function PosterComponent({ activityId, userId }: { activityId: number; userId: number }) {
|
|||
|
|
const { posterUrl, loading, error, fetchPoster } = usePoster(activityId, userId, 'default')
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
{loading && <p>加载中...</p>}
|
|||
|
|
{error && <p>错误: {error.message}</p>}
|
|||
|
|
{posterUrl && (
|
|||
|
|
<div>
|
|||
|
|
<img src={posterUrl} alt="分享海报" />
|
|||
|
|
<button onClick={() => fetchPoster()}>刷新海报</button>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### useLeaderboard
|
|||
|
|
|
|||
|
|
排行榜的专用Hook。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { useLeaderboard } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
function LeaderboardComponent({ activityId }: { activityId: number }) {
|
|||
|
|
const { entries, loading, error, pagination, fetchLeaderboard, changePage } = useLeaderboard(activityId)
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
{loading && <p>加载中...</p>}
|
|||
|
|
{error && <p>错误: {error.message}</p>}
|
|||
|
|
{entries && (
|
|||
|
|
<div>
|
|||
|
|
<ul>
|
|||
|
|
{entries.map((entry, index) => (
|
|||
|
|
<li key={entry.userId}>
|
|||
|
|
#{index + 1} - {entry.userName}: {entry.score}分
|
|||
|
|
</li>
|
|||
|
|
))}
|
|||
|
|
</ul>
|
|||
|
|
<button onClick={() => changePage(pagination.page - 1)} disabled={pagination.page === 0}>
|
|||
|
|
上一页
|
|||
|
|
</button>
|
|||
|
|
<span>第 {pagination.page + 1} 页</span>
|
|||
|
|
<button onClick={() => changePage(pagination.page + 1)} disabled={pagination.page >= pagination.totalPages - 1}>
|
|||
|
|
下一页
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎨 自定义主题
|
|||
|
|
|
|||
|
|
### 使用主题提供者
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
import { MosquitoProvider, MosquitoTheme } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
const customTheme: MosquitoTheme = {
|
|||
|
|
colors: {
|
|||
|
|
primary: '#ff6b00',
|
|||
|
|
secondary: '#6c757d',
|
|||
|
|
success: '#28a745',
|
|||
|
|
danger: '#dc3545',
|
|||
|
|
warning: '#ffc107',
|
|||
|
|
},
|
|||
|
|
components: {
|
|||
|
|
Button: {
|
|||
|
|
borderRadius: '8px',
|
|||
|
|
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
|||
|
|
},
|
|||
|
|
Card: {
|
|||
|
|
borderRadius: '12px',
|
|||
|
|
boxShadow: '0 4px 8px rgba(0,0,0,0.15)',
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function App() {
|
|||
|
|
return (
|
|||
|
|
<MosquitoProvider
|
|||
|
|
baseUrl="https://api.your-domain.com"
|
|||
|
|
apiKey="your-api-key"
|
|||
|
|
theme={customTheme}
|
|||
|
|
>
|
|||
|
|
<YourApp />
|
|||
|
|
</MosquitoProvider>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📝 TypeScript类型
|
|||
|
|
|
|||
|
|
### 类型定义
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import type {
|
|||
|
|
Activity,
|
|||
|
|
LeaderboardEntry,
|
|||
|
|
ShareMeta,
|
|||
|
|
PosterConfig,
|
|||
|
|
ApiResponse,
|
|||
|
|
MosquitoConfig,
|
|||
|
|
MosquitoTheme
|
|||
|
|
} from '@mosquito/react'
|
|||
|
|
|
|||
|
|
// Activity类型
|
|||
|
|
interface Activity {
|
|||
|
|
id: number
|
|||
|
|
name: string
|
|||
|
|
startTime: Date
|
|||
|
|
endTime: Date
|
|||
|
|
status: 'draft' | 'active' | 'completed'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LeaderboardEntry类型
|
|||
|
|
interface LeaderboardEntry {
|
|||
|
|
userId: number
|
|||
|
|
userName: string
|
|||
|
|
score: number
|
|||
|
|
rank?: number
|
|||
|
|
inviteCount?: number
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ShareMeta类型
|
|||
|
|
interface ShareMeta {
|
|||
|
|
title: string
|
|||
|
|
description: string
|
|||
|
|
image: string
|
|||
|
|
url: string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// PosterConfig类型
|
|||
|
|
interface PosterConfig {
|
|||
|
|
template: string
|
|||
|
|
imageUrl: string
|
|||
|
|
htmlUrl: string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ApiResponse类型
|
|||
|
|
interface ApiResponse<T> {
|
|||
|
|
code: number
|
|||
|
|
message: string
|
|||
|
|
data: T
|
|||
|
|
meta?: {
|
|||
|
|
page: number
|
|||
|
|
size: number
|
|||
|
|
total: number
|
|||
|
|
totalPages: number
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MosquitoConfig类型
|
|||
|
|
interface MosquitoConfig {
|
|||
|
|
baseUrl: string
|
|||
|
|
apiKey: string
|
|||
|
|
timeout?: number
|
|||
|
|
retryCount?: number
|
|||
|
|
enableLogging?: boolean
|
|||
|
|
theme?: MosquitoTheme
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MosquitoTheme类型
|
|||
|
|
interface MosquitoTheme {
|
|||
|
|
colors: {
|
|||
|
|
primary: string
|
|||
|
|
secondary: string
|
|||
|
|
success: string
|
|||
|
|
danger: string
|
|||
|
|
warning: string
|
|||
|
|
}
|
|||
|
|
components: {
|
|||
|
|
Button?: React.CSSProperties
|
|||
|
|
Card?: React.CSSProperties
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🧪 测试
|
|||
|
|
|
|||
|
|
### 单元测试
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|||
|
|
import { MosquitoProvider } from '@mosquito/react'
|
|||
|
|
import { MosquitoShareButton } from '@mosquito/react'
|
|||
|
|
|
|||
|
|
function renderWithProviders(ui: React.ReactElement) {
|
|||
|
|
return render(
|
|||
|
|
<MosquitoProvider
|
|||
|
|
baseUrl="https://test-api.com"
|
|||
|
|
apiKey="test-key"
|
|||
|
|
>
|
|||
|
|
{ui}
|
|||
|
|
</MosquitoProvider>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test('渲染分享按钮', () => {
|
|||
|
|
renderWithProviders(
|
|||
|
|
<MosquitoShareButton activityId={1} userId={100} />
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const button = screen.getByText('分享给好友')
|
|||
|
|
expect(button).toBeInTheDocument()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
test('点击按钮触发分享', async () => {
|
|||
|
|
renderWithProviders(
|
|||
|
|
<MosquitoShareButton activityId={1} userId={100} onCopy={mockOnCopy} />
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const button = screen.getByText('分享给好友')
|
|||
|
|
fireEvent.click(button)
|
|||
|
|
|
|||
|
|
await waitFor(() => {
|
|||
|
|
expect(mockOnCopy).toHaveBeenCalled()
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📚 最佳实践
|
|||
|
|
|
|||
|
|
### 1. 错误处理
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
function GoodErrorHandling() {
|
|||
|
|
const { getShareUrl, error } = useMosquito()
|
|||
|
|
const [localError, setLocalError] = useState<Error | null>(null)
|
|||
|
|
|
|||
|
|
const handleShare = async () => {
|
|||
|
|
try {
|
|||
|
|
await getShareUrl(1, 100)
|
|||
|
|
} catch (err) {
|
|||
|
|
setLocalError(err as Error)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<button onClick={handleShare}>分享</button>
|
|||
|
|
{(error || localError) && (
|
|||
|
|
<div className="error-message">
|
|||
|
|
{(error || localError)?.message}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 加载状态
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
function GoodLoadingState() {
|
|||
|
|
const { getShareUrl, loading } = useMosquito()
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<button onClick={() => getShareUrl(1, 100)} disabled={loading}>
|
|||
|
|
{loading ? '分享中...' : '分享给好友'}
|
|||
|
|
</button>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 类型安全
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
function TypeSafeComponent() {
|
|||
|
|
const [activity, setActivity] = useState<Activity | null>(null)
|
|||
|
|
const { getActivity } = useMosquito()
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
const loadActivity = async () => {
|
|||
|
|
const data = await getActivity(1)
|
|||
|
|
setActivity(data)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
loadActivity()
|
|||
|
|
}, [getActivity])
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
{activity && (
|
|||
|
|
<div>
|
|||
|
|
<h2>{activity.name}</h2>
|
|||
|
|
<p>开始时间: {activity.startTime.toLocaleDateString()}</p>
|
|||
|
|
<p>结束时间: {activity.endTime.toLocaleDateString()}</p>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🤝 贡献
|
|||
|
|
|
|||
|
|
欢迎提交Issue和Pull Request!
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*React组件库版本: v2.0.0*
|
|||
|
|
*最后更新: 2026-01-22*
|