mirror of
https://gh-proxy.org/https://github.com/tiajinsha/JKVideo
synced 2026-07-07 23:18:38 +08:00
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|||
|
|
import { getRelation, modifyRelation } from "../services/bilibili";
|
|||
|
|
import { useAuthStore } from "../store/authStore";
|
|||
|
|
import { getSecure } from "../utils/secureStorage";
|
|||
|
|
import { toast } from "../utils/toast";
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 关注 / 取消关注 UP 主。
|
|||
|
|
* - 未登录:toggle 时 toast 提示,按钮 disabled=false 仍允许点击
|
|||
|
|
* - 已登录但无 bili_jct:toggle 时 toast 提示让用户重登
|
|||
|
|
* - 正常路径:乐观更新 UI,请求失败回滚
|
|||
|
|
*/
|
|||
|
|
export function useFollow(mid: number | undefined) {
|
|||
|
|
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
|
|||
|
|
const [following, setFollowing] = useState(false);
|
|||
|
|
const [loading, setLoading] = useState(false);
|
|||
|
|
const inflightRef = useRef(false);
|
|||
|
|
|
|||
|
|
// 首次拉取 / mid 切换时刷新关注状态
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!mid || !isLoggedIn) {
|
|||
|
|
setFollowing(false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
let cancelled = false;
|
|||
|
|
getRelation(mid)
|
|||
|
|
.then((r) => {
|
|||
|
|
if (!cancelled) setFollowing(r.following);
|
|||
|
|
})
|
|||
|
|
.catch(() => {});
|
|||
|
|
return () => {
|
|||
|
|
cancelled = true;
|
|||
|
|
};
|
|||
|
|
}, [mid, isLoggedIn]);
|
|||
|
|
|
|||
|
|
const toggle = useCallback(async () => {
|
|||
|
|
if (!mid) return;
|
|||
|
|
if (!isLoggedIn) {
|
|||
|
|
toast("请先登录后再关注");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const biliJct = await getSecure("bili_jct");
|
|||
|
|
if (!biliJct) {
|
|||
|
|
toast("请重新登录后再使用关注功能");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (inflightRef.current) return;
|
|||
|
|
inflightRef.current = true;
|
|||
|
|
setLoading(true);
|
|||
|
|
const next = !following;
|
|||
|
|
setFollowing(next); // 乐观更新
|
|||
|
|
try {
|
|||
|
|
await modifyRelation(mid, next ? 1 : 2);
|
|||
|
|
} catch (e: any) {
|
|||
|
|
setFollowing(!next); // 失败回滚
|
|||
|
|
if (e?.message === "NO_CSRF") {
|
|||
|
|
toast("请重新登录后再使用关注功能");
|
|||
|
|
} else {
|
|||
|
|
toast(`操作失败:${e?.message || "未知错误"}`);
|
|||
|
|
}
|
|||
|
|
} finally {
|
|||
|
|
inflightRef.current = false;
|
|||
|
|
setLoading(false);
|
|||
|
|
}
|
|||
|
|
}, [mid, isLoggedIn, following]);
|
|||
|
|
|
|||
|
|
return { following, loading, toggle };
|
|||
|
|
}
|