diff --git a/frontend/src/pages/xray/dns/DnsTab.tsx b/frontend/src/pages/xray/dns/DnsTab.tsx index 4b3a0b6d4..9fade2acc 100644 --- a/frontend/src/pages/xray/dns/DnsTab.tsx +++ b/frontend/src/pages/xray/dns/DnsTab.tsx @@ -128,6 +128,26 @@ export default function DnsTab({ templateSettings, setTemplateSettings }: DnsTab return list.map((server, idx) => ({ key: idx, server })); }, [dns?.servers]); + // Stable callbacks: the column definitions in useDnsServerColumns are + // memoized, so they must be able to depend on these (see issue #5155) + const openEditServer = useCallback( + (idx: number) => { + setEditingServer((dns?.servers || [])[idx] || null); + setEditingIndex(idx); + setServerModalOpen(true); + }, + [dns?.servers], + ); + const deleteServer = useCallback( + (idx: number) => { + mutate((tt) => { + const cfg = tt.dns as DnsConfig | undefined; + if (cfg?.servers) cfg.servers.splice(idx, 1); + }); + }, + [mutate], + ); + const dnsColumns = useDnsServerColumns({ openEditServer, deleteServer }); function openAddServer() { @@ -135,11 +155,6 @@ export default function DnsTab({ templateSettings, setTemplateSettings }: DnsTab setEditingIndex(null); setServerModalOpen(true); } - function openEditServer(idx: number) { - setEditingServer((dns?.servers || [])[idx] || null); - setEditingIndex(idx); - setServerModalOpen(true); - } function onServerConfirm(value: DnsServerValue) { mutate((tt) => { if (!tt.dns) return; @@ -150,12 +165,6 @@ export default function DnsTab({ templateSettings, setTemplateSettings }: DnsTab }); setServerModalOpen(false); } - function deleteServer(idx: number) { - mutate((tt) => { - const cfg = tt.dns as DnsConfig | undefined; - if (cfg?.servers) cfg.servers.splice(idx, 1); - }); - } function clearAllServers() { modal.confirm({ title: t('pages.xray.dns.clearAllTitle'), @@ -182,6 +191,28 @@ export default function DnsTab({ templateSettings, setTemplateSettings }: DnsTab return list.map((entry, idx) => ({ key: idx, ...entry })); }, [templateSettings?.fakedns]); + const deleteFakedns = useCallback( + (idx: number) => { + mutate((tt) => { + const list = tt.fakedns as FakednsRow[] | undefined; + if (!list) return; + list.splice(idx, 1); + if (list.length === 0) tt.fakedns = null; + }); + }, + [mutate], + ); + const updateFakednsField = useCallback( + (idx: number, field: 'ipPool' | 'poolSize', value: string | number) => { + mutate((tt) => { + const list = tt.fakedns as FakednsRow[] | undefined; + if (!list?.[idx]) return; + (list[idx] as unknown as Record)[field] = value; + }); + }, + [mutate], + ); + const fakednsColumns = useFakednsColumns({ deleteFakedns, updateFakednsField }); function addFakedns() { @@ -190,21 +221,6 @@ export default function DnsTab({ templateSettings, setTemplateSettings }: DnsTab (tt.fakedns as FakednsRow[]).push(DEFAULT_FAKEDNS()); }); } - function deleteFakedns(idx: number) { - mutate((tt) => { - const list = tt.fakedns as FakednsRow[] | undefined; - if (!list) return; - list.splice(idx, 1); - if (list.length === 0) tt.fakedns = null; - }); - } - function updateFakednsField(idx: number, field: 'ipPool' | 'poolSize', value: string | number) { - mutate((tt) => { - const list = tt.fakedns as FakednsRow[] | undefined; - if (!list?.[idx]) return; - (list[idx] as unknown as Record)[field] = value; - }); - } const items = useMemo(() => { const out = [ diff --git a/frontend/src/pages/xray/dns/useDnsColumns.tsx b/frontend/src/pages/xray/dns/useDnsColumns.tsx index 818b5a3c9..bb4bcbfcc 100644 --- a/frontend/src/pages/xray/dns/useDnsColumns.tsx +++ b/frontend/src/pages/xray/dns/useDnsColumns.tsx @@ -61,8 +61,7 @@ export function useDnsServerColumns({ render: (_v, record) => {expectedIPsFor(record.server)}, }, ], - // eslint-disable-next-line react-hooks/exhaustive-deps - [t], + [t, openEditServer, deleteServer], ); } @@ -116,7 +115,6 @@ export function useFakednsColumns({ ), }, ], - // eslint-disable-next-line react-hooks/exhaustive-deps - [], + [deleteFakedns, updateFakednsField], ); }