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