Переглянути джерело

fix: DNS server edit modal showing defaults instead of saved values (#5155)

The DNS server table columns were memoized with only [t] as deps, so
they permanently captured the first render's openEditServer callback,
which closed over the initial (null) dns settings. Clicking Edit then
resolved the server to null and the modal fell back to default values.

Stabilize openEditServer/deleteServer (and the fakedns equivalents)
with useCallback and include them in the column memo deps so the
columns refresh whenever the servers list changes.
MHSanaei 15 годин тому
батько
коміт
1508666e52

+ 42 - 26
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<string, unknown>)[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<string, unknown>)[field] = value;
-    });
-  }
 
   const items = useMemo(() => {
     const out = [

+ 2 - 4
frontend/src/pages/xray/dns/useDnsColumns.tsx

@@ -61,8 +61,7 @@ export function useDnsServerColumns({
         render: (_v, record) => <span className="muted">{expectedIPsFor(record.server)}</span>,
       },
     ],
-    // 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],
   );
 }