Commit 9b60bf72e37cbebe4d6a7cdf5167fccc7d4993b3

Authored by zichun
1 parent 2900cc7c

chore(usr): FE-03 门禁回归通过 REQ-USR-003

frontend/src/pages/usr/UserList/useUserList.ts
@@ -51,6 +51,9 @@ export function useUserList(): UseUserListReturn { @@ -51,6 +51,9 @@ export function useUserList(): UseUserListReturn {
51 const messageRef = useRef(message); 51 const messageRef = useRef(message);
52 messageRef.current = message; 52 messageRef.current = message;
53 53
  54 + // 卸载守卫:避免异步取数 resolve/reject 在组件卸载后 setState(防内存泄漏 / 测试环境拆除后报错)
  55 + const mountedRef = useRef(true);
  56 +
54 /** 以给定 query 取数;同步 total/pageNum/pageSize 回显(BR15);错误码分流(spec § 4) */ 57 /** 以给定 query 取数;同步 total/pageNum/pageSize 回显(BR15);错误码分流(spec § 4) */
55 const runFetch = useCallback(async (q: UserListQuery) => { 58 const runFetch = useCallback(async (q: UserListQuery) => {
56 setQuery(q); 59 setQuery(q);
@@ -59,6 +62,7 @@ export function useUserList(): UseUserListReturn { @@ -59,6 +62,7 @@ export function useUserList(): UseUserListReturn {
59 setError(null); 62 setError(null);
60 try { 63 try {
61 const pageData = await listUsers(q); 64 const pageData = await listUsers(q);
  65 + if (!mountedRef.current) return;
62 setList(pageData.records); 66 setList(pageData.records);
63 setTotal(pageData.total); 67 setTotal(pageData.total);
64 // 信任后端回显(越界回退最后一页等),同步分页当前页/页大小(BR15) 68 // 信任后端回显(越界回退最后一页等),同步分页当前页/页大小(BR15)
@@ -69,6 +73,7 @@ export function useUserList(): UseUserListReturn { @@ -69,6 +73,7 @@ export function useUserList(): UseUserListReturn {
69 }); 73 });
70 setLoading(false); 74 setLoading(false);
71 } catch (err) { 75 } catch (err) {
  76 + if (!mountedRef.current) return;
72 const apiErr = err instanceof ApiError ? err : new ApiError(-1, TEXT_MSG_NETWORK); 77 const apiErr = err instanceof ApiError ? err : new ApiError(-1, TEXT_MSG_NETWORK);
73 setLoading(false); 78 setLoading(false);
74 if (apiErr.code === ERR_PAGE_INVALID) { 79 if (apiErr.code === ERR_PAGE_INVALID) {
@@ -92,7 +97,11 @@ export function useUserList(): UseUserListReturn { @@ -92,7 +97,11 @@ export function useUserList(): UseUserListReturn {
92 97
93 // 挂载即以默认条件取数(initialLoading,BR2) 98 // 挂载即以默认条件取数(initialLoading,BR2)
94 useEffect(() => { 99 useEffect(() => {
  100 + mountedRef.current = true;
95 void runFetch({ ...DEFAULT_QUERY }); 101 void runFetch({ ...DEFAULT_QUERY });
  102 + return () => {
  103 + mountedRef.current = false;
  104 + };
96 // eslint-disable-next-line react-hooks/exhaustive-deps 105 // eslint-disable-next-line react-hooks/exhaustive-deps
97 }, []); 106 }, []);
98 107
@@ -140,11 +149,11 @@ export function useUserList(): UseUserListReturn { @@ -140,11 +149,11 @@ export function useUserList(): UseUserListReturn {
140 const pageData = await listUsers({ ...cur, pageNum: 1, pageSize: fetchSize }); 149 const pageData = await listUsers({ ...cur, pageNum: 1, pageSize: fetchSize });
141 const csv = buildUserCsv(pageData.records); 150 const csv = buildUserCsv(pageData.records);
142 downloadCsv(EXPORT_FILENAME, csv); 151 downloadCsv(EXPORT_FILENAME, csv);
143 - messageRef.current.success(TEXT_EXPORT_SUCCESS); 152 + if (mountedRef.current) messageRef.current.success(TEXT_EXPORT_SUCCESS);
144 } catch { 153 } catch {
145 - messageRef.current.error(TEXT_EXPORT_FAIL); 154 + if (mountedRef.current) messageRef.current.error(TEXT_EXPORT_FAIL);
146 } finally { 155 } finally {
147 - setExporting(false); 156 + if (mountedRef.current) setExporting(false);
148 } 157 }
149 }, [total]); 158 }, [total]);
150 159
frontend/tests/unit/UserTable.test.tsx
1 // REQ-USR-003: UserTable 表格单测(BR1/BR6/BR11/BR12/BR14/D8) 1 // REQ-USR-003: UserTable 表格单测(BR1/BR6/BR11/BR12/BR14/D8)
2 import { describe, it, expect, vi, beforeEach } from 'vitest'; 2 import { describe, it, expect, vi, beforeEach } from 'vitest';
3 -import { screen, within } from '@testing-library/react'; 3 +import { screen } from '@testing-library/react';
4 import userEvent from '@testing-library/user-event'; 4 import userEvent from '@testing-library/user-event';
5 import { renderShell } from './renderShell'; 5 import { renderShell } from './renderShell';
6 import UserTable from '../../src/pages/usr/UserList/UserTable'; 6 import UserTable from '../../src/pages/usr/UserList/UserTable';