feat(web): 定时拉取优化——静默刷新不闪loading + AdminTable稳定排序/键控不重排
- useAsyncData: dataRef跟踪,首次setLoading(骨架),已有data时不设loading(静默后台拉),成功setData/失败保留旧data - AdminTable: rows 按 rowKey 升序稳定排序(useMemo,同批数据顺序稳定不跳),稳定key diff复用DOM不整页重绘,error&&!hasRows才显示错误(保留旧表) - 受益: 所有useAsyncData/AdminTable面板页(会话/记忆/渠道/IoT/插件/人格/用户/RAG/LLM/自动化/可观测/仪表盘) - npm run build绿(83模块)
This commit is contained in:
1 parent
eaca8dc8cc
commit
e9df928072
2 files changed
+32
-8
No files matched your search
@@ -8,18 +8,26 @@ interface AsyncState<T> {
|
||||
}
|
||||
|
||||
/** Runs an async factory on mount (and on reload), tracking loading/error so
|
||||
* every API-backed surface has a complete state. Best-effort, no `any`. */
|
||||
* every API-backed surface has a complete state. Best-effort, no `any`.
|
||||
*
|
||||
* Reloads after the first load are *silent*: once data is on screen the old
|
||||
* list is kept (no loading flicker) and only replaced when fresh data lands.
|
||||
* If a silent refresh fails, the old data is preserved and the error recorded
|
||||
* for the next state read. The first (data-less) load still shows loading. */
|
||||
export function useAsyncData<T>(fn: () => Promise<T>, deps: readonly unknown[] = []): AsyncState<T> {
|
||||
const [data, setData] = useState<T | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const dataRef = useRef<T | null>(null);
|
||||
dataRef.current = data;
|
||||
const fnRef = useRef(fn);
|
||||
fnRef.current = fn;
|
||||
const depsKey = deps.join("\u0000");
|
||||
|
||||
const run = useCallback(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
const first = dataRef.current == null;
|
||||
if (first) setLoading(true);
|
||||
setError(null);
|
||||
fnRef
|
||||
.current()
|
||||
@@ -30,7 +38,7 @@ export function useAsyncData<T>(fn: () => Promise<T>, deps: readonly unknown[] =
|
||||
if (!cancelled) setError(err instanceof Error ? err.message : "加载失败");
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
if (!cancelled && first) setLoading(false);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
|
||||
Reference in new issue
Block a user