mirror of
https://gh-proxy.org/https://github.com/tiajinsha/JKVideo
synced 2026-07-07 23:18:38 +08:00
为尊重知识产权及相关法律法规,本仓库即日起停止后续维护与更新,不再接受新的 Issue 和 Pull Request。 现有代码仅作学习参考保留,请勿将本项目用于任何商业或违法用途。 感谢所有支持过本项目的朋友。
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 };
|
||
}
|