Appearance
Vue / React 适配层
两套适配层共享同一 hooks 语义,返回结构几乎一致;迁移成本为零。源码入口:src/vue/index.ts、src/react/index.ts(v0.2.0 逐项核对)。
usePartakeUpload
ts
usePartakeUpload(opts: ManagerOptions): UsePartakeUploadManagerOptions 见 core 文档:controlBase 必填,其余全可选(默认值见配置表)。
⚠️ hook 语义:
opts仅在首次调用生效(Vue 侧 setup 固化;React 侧useRef惰性初始化)——core 无配置热更语义,后续渲染传入的新 opts 被忽略。
返回结构
ts
type UsePartakeUpload = {
// 响应式状态
tasks: Task[]; // vue: shallowReactive(重建驱动渲染); react: version memo 快照
stats: { total: number; uploading: number; completed: number; failed: number; error: number };
// vue: computed; react: version memo。failed 口径含 quarantined
version: number; // ⚠️ 仅 react 返回(useSyncExternalStore 快照值;vue 无需暴露)
// 命令式控制(vue: 直接绑定 manager 方法; react: 构造时绑定,引用稳定)
addFiles(files: File[]): Task[];
start(taskId?: string): void;
startAll(): void;
abort(taskId: string): Promise<void>;
abortAll(): Promise<void>;
pause(taskId: string): Promise<void>;
pauseAll(): Promise<void>;
resume(taskId: string): void;
resumeAll(): void;
removeTask(taskId: string): Promise<void>;
retryTask(taskId: string): void;
getTask(taskId: string): Task | undefined;
downloadUrl(fileId: string): Promise<{ url: string; expiresAt: number }>;
};方法语义与 PartakeUploadManager 完全一致。
downloadUrl
completed 态取下载预签名地址;quarantined 后端返回 409 → 抛 Error(非 PartakeError):
ts
const { url, expiresAt } = await downloadUrl(task.fileId!);
location.assign(url); // 或 <a :href="url"> 打开下载Vue 3
ts
import { usePartakeUpload } from '@pidaqing/uploader/vue';实现要点(v0.2 批次 B 修正):manager 突变的是原始 Task 引用,绕过 reactive proxy 的 set trap——适配层以 shallowReactive 数组 + 订阅重建(splice 清空再 push,元素保持原始引用)驱动渲染;进度类高频更新经 manager 100ms 合并,恰好是渲染节流。
ts
const { tasks, stats, addFiles, pause, resume, downloadUrl } = usePartakeUpload({
controlBase: '/api/partake',
speedLimit: 1024 * 1024, // 1MB/s
urlWaterline: 'auto',
});
addFiles([file]); // hash → 秒传探测 → 分片 PUT → complete(自动启动)
watch(() => stats.value.completed, (n) => console.log('完成数', n));stats 是 computed——模板直接使用即可;tasks 变更即渲染(含 paused 徽标所需字段)。
React 18+
ts
import { usePartakeUpload } from '@pidaqing/uploader/react';实现要点:基于 useSyncExternalStore 订阅 manager.version(任意 Task 突变/增删递增)——React 无 Proxy 细粒度追踪,tasks/stats 按 version memo;命令式方法引用稳定,effect 依赖数组安全;第三参数快照 = SSR/hydration 就绪(Next.js 开箱即用)。
tsx
function App() {
const { tasks, stats, version, addFiles, pause, resume } = usePartakeUpload({
controlBase: '/api/partake',
});
useEffect(() => {
console.log('版本变更', version); // version 变化即任务集变化
}, [version]);
return (
<div>
<p>完成 {stats.completed} / 总数 {stats.total}</p>
<button onClick={() => addFiles(pickFiles())}>添加</button>
<ul>
{tasks.map((t) => (
<li key={t.id}>
{t.fileName} — {Math.round(t.progress * 100)}%{' '}
{t.paused && <button onClick={() => resume(t.id)}>继续</button>}
<button onClick={() => pause(t.id)}>暂停</button>
</li>
))}
</ul>
</div>
);
}两适配层差异速查
| 维度 | Vue | React |
|---|---|---|
| 响应式机制 | shallowReactive + 订阅重建 | useSyncExternalStore + version memo |
version | 不返回 | 返回 |
stats 类型 | ComputedRef<Stats> | Stats(普通对象) |
| 渲染触发 | 数组 length/重建 | version 快照变化 |
| SSR | — | 第三参数 getSnapshot(hydrate 安全) |