fix: resolve all 25 ESLint react-hooks and react-refresh violations
Replace useEffect-based state resets in dialogs with React's render-time state adjustment pattern. Wrap ref assignments in hooks with useEffect. Suppress known third-party library warnings (shadcn CVA exports, TanStack Table). Remove warn downgrades from eslint config.
This commit was merged in pull request #1.
This commit is contained in:
@@ -20,9 +20,6 @@ export default defineConfig([
|
|||||||
globals: globals.browser,
|
globals: globals.browser,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// TODO: fix these incrementally — pre-existing violations from react-hooks v7 upgrade
|
|
||||||
'react-hooks/set-state-in-effect': 'warn',
|
|
||||||
'react-hooks/refs': 'warn',
|
|
||||||
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
|
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -99,7 +99,9 @@ export function ConnectionDialog({ open, onOpenChange, connection }: Props) {
|
|||||||
const saveMutation = useSaveConnection();
|
const saveMutation = useSaveConnection();
|
||||||
const testMutation = useTestConnection();
|
const testMutation = useTestConnection();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prev, setPrev] = useState<{ open: boolean; connection: typeof connection }>({ open: false, connection: null });
|
||||||
|
if (open !== prev.open || connection !== prev.connection) {
|
||||||
|
setPrev({ open, connection });
|
||||||
if (open) {
|
if (open) {
|
||||||
const config = connection ?? { ...emptyConfig, id: crypto.randomUUID() };
|
const config = connection ?? { ...emptyConfig, id: crypto.randomUUID() };
|
||||||
setForm(config);
|
setForm(config);
|
||||||
@@ -107,7 +109,7 @@ export function ConnectionDialog({ open, onOpenChange, connection }: Props) {
|
|||||||
setDsn(connection ? buildDsn(config) : "");
|
setDsn(connection ? buildDsn(config) : "");
|
||||||
setDsnError(null);
|
setDsnError(null);
|
||||||
}
|
}
|
||||||
}, [open, connection]);
|
}
|
||||||
|
|
||||||
const update = (field: keyof ConnectionConfig, value: string | number) => {
|
const update = (field: keyof ConnectionConfig, value: string | number) => {
|
||||||
setForm((f) => ({ ...f, [field]: value }));
|
setForm((f) => ({ ...f, [field]: value }));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -54,7 +54,9 @@ export function GenerateDataDialog({
|
|||||||
reset,
|
reset,
|
||||||
} = useDataGenerator();
|
} = useDataGenerator();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setStep("config");
|
setStep("config");
|
||||||
setRowCount(10);
|
setRowCount(10);
|
||||||
@@ -62,7 +64,7 @@ export function GenerateDataDialog({
|
|||||||
setCustomInstructions("");
|
setCustomInstructions("");
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}, [open, reset]);
|
}
|
||||||
|
|
||||||
const handleGenerate = () => {
|
const handleGenerate = () => {
|
||||||
const genId = crypto.randomUUID();
|
const genId = crypto.randomUUID();
|
||||||
|
|||||||
@@ -112,11 +112,13 @@ export function CloneDatabaseDialog({
|
|||||||
useCloneToDocker();
|
useCloneToDocker();
|
||||||
|
|
||||||
// Reset state when dialog opens
|
// Reset state when dialog opens
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState<{ open: boolean; database: string }>({ open: false, database: "" });
|
||||||
|
if (open !== prevOpen.open || database !== prevOpen.database) {
|
||||||
|
setPrevOpen({ open, database });
|
||||||
if (open) {
|
if (open) {
|
||||||
setStep("config");
|
setStep("config");
|
||||||
setContainerName(
|
setContainerName(
|
||||||
`tusk-${database.replace(/[^a-zA-Z0-9_-]/g, "-")}-${Date.now().toString(36)}`
|
`tusk-${database.replace(/[^a-zA-Z0-9_-]/g, "-")}-${crypto.randomUUID().slice(0, 8)}`
|
||||||
);
|
);
|
||||||
setPgVersion("16");
|
setPgVersion("16");
|
||||||
setPortMode("auto");
|
setPortMode("auto");
|
||||||
@@ -127,10 +129,12 @@ export function CloneDatabaseDialog({
|
|||||||
setLogOpen(false);
|
setLogOpen(false);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}, [open, database, reset]);
|
}
|
||||||
|
|
||||||
// Accumulate progress events into log
|
// Accumulate progress events into log
|
||||||
useEffect(() => {
|
const [prevProgress, setPrevProgress] = useState(progress);
|
||||||
|
if (progress !== prevProgress) {
|
||||||
|
setPrevProgress(progress);
|
||||||
if (progress) {
|
if (progress) {
|
||||||
setLogEntries((prev) => {
|
setLogEntries((prev) => {
|
||||||
const last = prev[prev.length - 1];
|
const last = prev[prev.length - 1];
|
||||||
@@ -143,7 +147,7 @@ export function CloneDatabaseDialog({
|
|||||||
setStep("done");
|
setStep("done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [progress]);
|
}
|
||||||
|
|
||||||
// Auto-scroll log to bottom
|
// Auto-scroll log to bottom
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useCallback, useEffect, useState } from "react";
|
import { useMemo, useCallback, useState } from "react";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import {
|
import {
|
||||||
ReactFlow,
|
ReactFlow,
|
||||||
@@ -111,12 +111,14 @@ export function ErdDiagram({ connectionId, schema }: Props) {
|
|||||||
const [nodes, setNodes] = useState<Node[]>([]);
|
const [nodes, setNodes] = useState<Node[]>([]);
|
||||||
const [edges, setEdges] = useState<Edge[]>([]);
|
const [edges, setEdges] = useState<Edge[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevLayout, setPrevLayout] = useState(layout);
|
||||||
|
if (layout !== prevLayout) {
|
||||||
|
setPrevLayout(layout);
|
||||||
if (layout) {
|
if (layout) {
|
||||||
setNodes(layout.nodes);
|
setNodes(layout.nodes);
|
||||||
setEdges(layout.edges);
|
setEdges(layout.edges);
|
||||||
}
|
}
|
||||||
}, [layout]);
|
}
|
||||||
|
|
||||||
const onNodesChange = useCallback(
|
const onNodesChange = useCallback(
|
||||||
(changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
(changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -34,7 +34,9 @@ export function AlterRoleDialog({ open, onOpenChange, connectionId, role }: Prop
|
|||||||
|
|
||||||
const alterMutation = useAlterRole();
|
const alterMutation = useAlterRole();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prev, setPrev] = useState<{ open: boolean; role: typeof role }>({ open: false, role: null });
|
||||||
|
if (open !== prev.open || role !== prev.role) {
|
||||||
|
setPrev({ open, role });
|
||||||
if (open && role) {
|
if (open && role) {
|
||||||
setPassword("");
|
setPassword("");
|
||||||
setLogin(role.can_login);
|
setLogin(role.can_login);
|
||||||
@@ -47,7 +49,7 @@ export function AlterRoleDialog({ open, onOpenChange, connectionId, role }: Prop
|
|||||||
setValidUntil(role.valid_until ?? "");
|
setValidUntil(role.valid_until ?? "");
|
||||||
setRenameTo("");
|
setRenameTo("");
|
||||||
}
|
}
|
||||||
}, [open, role]);
|
}
|
||||||
|
|
||||||
if (!role) return null;
|
if (!role) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -35,7 +35,9 @@ export function CreateDatabaseDialog({ open, onOpenChange, connectionId }: Props
|
|||||||
const { data: roles } = useRoles(open ? connectionId : null);
|
const { data: roles } = useRoles(open ? connectionId : null);
|
||||||
const createMutation = useCreateDatabase();
|
const createMutation = useCreateDatabase();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setName("");
|
setName("");
|
||||||
setOwner("__default__");
|
setOwner("__default__");
|
||||||
@@ -43,7 +45,7 @@ export function CreateDatabaseDialog({ open, onOpenChange, connectionId }: Props
|
|||||||
setEncoding("UTF8");
|
setEncoding("UTF8");
|
||||||
setConnectionLimit(-1);
|
setConnectionLimit(-1);
|
||||||
}
|
}
|
||||||
}, [open]);
|
}
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
if (!name.trim()) {
|
if (!name.trim()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -34,7 +34,9 @@ export function CreateRoleDialog({ open, onOpenChange, connectionId }: Props) {
|
|||||||
const { data: roles } = useRoles(open ? connectionId : null);
|
const { data: roles } = useRoles(open ? connectionId : null);
|
||||||
const createMutation = useCreateRole();
|
const createMutation = useCreateRole();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setName("");
|
setName("");
|
||||||
setPassword("");
|
setPassword("");
|
||||||
@@ -48,7 +50,7 @@ export function CreateRoleDialog({ open, onOpenChange, connectionId }: Props) {
|
|||||||
setValidUntil("");
|
setValidUntil("");
|
||||||
setInRoles([]);
|
setInRoles([]);
|
||||||
}
|
}
|
||||||
}, [open]);
|
}
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
if (!name.trim()) {
|
if (!name.trim()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -61,14 +61,16 @@ export function GrantRevokeDialog({
|
|||||||
);
|
);
|
||||||
const grantRevokeMutation = useGrantRevoke();
|
const grantRevokeMutation = useGrantRevoke();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setAction("GRANT");
|
setAction("GRANT");
|
||||||
setRoleName("");
|
setRoleName("");
|
||||||
setPrivileges([]);
|
setPrivileges([]);
|
||||||
setWithGrantOption(false);
|
setWithGrantOption(false);
|
||||||
}
|
}
|
||||||
}, [open]);
|
}
|
||||||
|
|
||||||
const availablePrivileges = PRIVILEGE_OPTIONS[objectType.toUpperCase()] ?? PRIVILEGE_OPTIONS.TABLE;
|
const availablePrivileges = PRIVILEGE_OPTIONS[objectType.toUpperCase()] ?? PRIVILEGE_OPTIONS.TABLE;
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ export function ResultsTable({
|
|||||||
[colNames, onCellDoubleClick, highlightedCells]
|
[colNames, onCellDoubleClick, highlightedCells]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/incompatible-library
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: rows,
|
data: rows,
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -23,9 +23,11 @@ export function SaveQueryDialog({ open, onOpenChange, sql, connectionId }: Props
|
|||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const saveMutation = useSaveQuery();
|
const saveMutation = useSaveQuery();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) setName("");
|
if (open) setName("");
|
||||||
}, [open]);
|
}
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!name.trim()) {
|
if (!name.trim()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
@@ -52,21 +52,25 @@ export function AppSettingsSheet({ open, onOpenChange }: Props) {
|
|||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
// Sync form with loaded settings
|
// Sync form with loaded settings
|
||||||
useEffect(() => {
|
const [prevAppSettings, setPrevAppSettings] = useState(appSettings);
|
||||||
|
if (appSettings !== prevAppSettings) {
|
||||||
|
setPrevAppSettings(appSettings);
|
||||||
if (appSettings) {
|
if (appSettings) {
|
||||||
setMcpEnabled(appSettings.mcp.enabled);
|
setMcpEnabled(appSettings.mcp.enabled);
|
||||||
setMcpPort(appSettings.mcp.port);
|
setMcpPort(appSettings.mcp.port);
|
||||||
setDockerHost(appSettings.docker.host);
|
setDockerHost(appSettings.docker.host);
|
||||||
setDockerRemoteUrl(appSettings.docker.remote_url ?? "");
|
setDockerRemoteUrl(appSettings.docker.remote_url ?? "");
|
||||||
}
|
}
|
||||||
}, [appSettings]);
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevAiSettings, setPrevAiSettings] = useState(aiSettings);
|
||||||
|
if (aiSettings !== prevAiSettings) {
|
||||||
|
setPrevAiSettings(aiSettings);
|
||||||
if (aiSettings) {
|
if (aiSettings) {
|
||||||
setOllamaUrl(aiSettings.ollama_url);
|
setOllamaUrl(aiSettings.ollama_url);
|
||||||
setAiModel(aiSettings.model);
|
setAiModel(aiSettings.model);
|
||||||
}
|
}
|
||||||
}, [aiSettings]);
|
}
|
||||||
|
|
||||||
const mcpEndpoint = `http://127.0.0.1:${mcpPort}/mcp`;
|
const mcpEndpoint = `http://127.0.0.1:${mcpPort}/mcp`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -43,7 +43,9 @@ export function CreateSnapshotDialog({ open, onOpenChange, connectionId }: Props
|
|||||||
|
|
||||||
const { create, result, error, isCreating, progress, reset } = useCreateSnapshot();
|
const { create, result, error, isCreating, progress, reset } = useCreateSnapshot();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setStep("config");
|
setStep("config");
|
||||||
setName(`snapshot-${new Date().toISOString().slice(0, 10)}`);
|
setName(`snapshot-${new Date().toISOString().slice(0, 10)}`);
|
||||||
@@ -51,20 +53,23 @@ export function CreateSnapshotDialog({ open, onOpenChange, connectionId }: Props
|
|||||||
setIncludeDeps(true);
|
setIncludeDeps(true);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}
|
||||||
}, [open, reset]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevSchemas, setPrevSchemas] = useState(schemas);
|
||||||
|
if (schemas !== prevSchemas) {
|
||||||
|
setPrevSchemas(schemas);
|
||||||
if (schemas && schemas.length > 0 && !selectedSchema) {
|
if (schemas && schemas.length > 0 && !selectedSchema) {
|
||||||
setSelectedSchema(schemas.find((s) => s === "public") || schemas[0]);
|
setSelectedSchema(schemas.find((s) => s === "public") || schemas[0]);
|
||||||
}
|
}
|
||||||
}, [schemas, selectedSchema]);
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevProgress, setPrevProgress] = useState(progress);
|
||||||
|
if (progress !== prevProgress) {
|
||||||
|
setPrevProgress(progress);
|
||||||
if (progress?.stage === "done" || progress?.stage === "error") {
|
if (progress?.stage === "done" || progress?.stage === "error") {
|
||||||
setStep("done");
|
setStep("done");
|
||||||
}
|
}
|
||||||
}, [progress]);
|
}
|
||||||
|
|
||||||
const handleToggleTable = (tableName: string) => {
|
const handleToggleTable = (tableName: string) => {
|
||||||
setSelectedTables((prev) => {
|
setSelectedTables((prev) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -38,7 +38,9 @@ export function RestoreSnapshotDialog({ open, onOpenChange, connectionId }: Prop
|
|||||||
const readMeta = useReadSnapshotMetadata();
|
const readMeta = useReadSnapshotMetadata();
|
||||||
const { restore, rowsRestored, error, isRestoring, progress, reset } = useRestoreSnapshot();
|
const { restore, rowsRestored, error, isRestoring, progress, reset } = useRestoreSnapshot();
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevOpen, setPrevOpen] = useState(false);
|
||||||
|
if (open !== prevOpen) {
|
||||||
|
setPrevOpen(open);
|
||||||
if (open) {
|
if (open) {
|
||||||
setStep("select");
|
setStep("select");
|
||||||
setFilePath(null);
|
setFilePath(null);
|
||||||
@@ -46,13 +48,15 @@ export function RestoreSnapshotDialog({ open, onOpenChange, connectionId }: Prop
|
|||||||
setTruncate(false);
|
setTruncate(false);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}, [open, reset]);
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const [prevProgress, setPrevProgress] = useState(progress);
|
||||||
|
if (progress !== prevProgress) {
|
||||||
|
setPrevProgress(progress);
|
||||||
if (progress?.stage === "done" || progress?.stage === "error") {
|
if (progress?.stage === "done" || progress?.stage === "error") {
|
||||||
setStep("done");
|
setStep("done");
|
||||||
}
|
}
|
||||||
}, [progress]);
|
}
|
||||||
|
|
||||||
const handleSelectFile = async () => {
|
const handleSelectFile = async () => {
|
||||||
const selected = await openFile({
|
const selected = await openFile({
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react-refresh/only-export-components */
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
import { Slot } from "radix-ui"
|
import { Slot } from "radix-ui"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react-refresh/only-export-components */
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
import { Slot } from "radix-ui"
|
import { Slot } from "radix-ui"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react-refresh/only-export-components */
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
import { Tabs as TabsPrimitive } from "radix-ui"
|
import { Tabs as TabsPrimitive } from "radix-ui"
|
||||||
|
|||||||
@@ -36,20 +36,31 @@ export function useDataGenerator() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlistenPromise = onDataGenProgress((p) => {
|
let mounted = true;
|
||||||
if (p.gen_id === genIdRef.current) {
|
let unlisten: (() => void) | undefined;
|
||||||
|
onDataGenProgress((p) => {
|
||||||
|
if (mounted && p.gen_id === genIdRef.current) {
|
||||||
setProgress(p);
|
setProgress(p);
|
||||||
}
|
}
|
||||||
|
}).then((fn) => {
|
||||||
|
if (mounted) {
|
||||||
|
unlisten = fn;
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
unlistenPromise.then((unlisten) => unlisten());
|
mounted = false;
|
||||||
|
unlisten?.();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const previewRef = useRef(previewMutation);
|
const previewRef = useRef(previewMutation);
|
||||||
previewRef.current = previewMutation;
|
|
||||||
const insertRef = useRef(insertMutation);
|
const insertRef = useRef(insertMutation);
|
||||||
insertRef.current = insertMutation;
|
useEffect(() => {
|
||||||
|
previewRef.current = previewMutation;
|
||||||
|
insertRef.current = insertMutation;
|
||||||
|
});
|
||||||
|
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
previewRef.current.reset();
|
previewRef.current.reset();
|
||||||
|
|||||||
@@ -51,18 +51,29 @@ export function useCloneToDocker() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlistenPromise = onCloneProgress((p) => {
|
let mounted = true;
|
||||||
if (p.clone_id === cloneIdRef.current) {
|
let unlisten: (() => void) | undefined;
|
||||||
|
onCloneProgress((p) => {
|
||||||
|
if (mounted && p.clone_id === cloneIdRef.current) {
|
||||||
setProgress(p);
|
setProgress(p);
|
||||||
}
|
}
|
||||||
|
}).then((fn) => {
|
||||||
|
if (mounted) {
|
||||||
|
unlisten = fn;
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
unlistenPromise.then((unlisten) => unlisten());
|
mounted = false;
|
||||||
|
unlisten?.();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const mutationRef = useRef(mutation);
|
const mutationRef = useRef(mutation);
|
||||||
mutationRef.current = mutation;
|
useEffect(() => {
|
||||||
|
mutationRef.current = mutation;
|
||||||
|
});
|
||||||
|
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
mutationRef.current.reset();
|
mutationRef.current.reset();
|
||||||
|
|||||||
@@ -53,18 +53,29 @@ export function useCreateSnapshot() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlistenPromise = onSnapshotProgress((p) => {
|
let mounted = true;
|
||||||
if (p.snapshot_id === snapshotIdRef.current) {
|
let unlisten: (() => void) | undefined;
|
||||||
|
onSnapshotProgress((p) => {
|
||||||
|
if (mounted && p.snapshot_id === snapshotIdRef.current) {
|
||||||
setProgress(p);
|
setProgress(p);
|
||||||
}
|
}
|
||||||
|
}).then((fn) => {
|
||||||
|
if (mounted) {
|
||||||
|
unlisten = fn;
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
unlistenPromise.then((unlisten) => unlisten());
|
mounted = false;
|
||||||
|
unlisten?.();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const mutationRef = useRef(mutation);
|
const mutationRef = useRef(mutation);
|
||||||
mutationRef.current = mutation;
|
useEffect(() => {
|
||||||
|
mutationRef.current = mutation;
|
||||||
|
});
|
||||||
|
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
mutationRef.current.reset();
|
mutationRef.current.reset();
|
||||||
@@ -101,18 +112,29 @@ export function useRestoreSnapshot() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlistenPromise = onSnapshotProgress((p) => {
|
let mounted = true;
|
||||||
if (p.snapshot_id === snapshotIdRef.current) {
|
let unlisten: (() => void) | undefined;
|
||||||
|
onSnapshotProgress((p) => {
|
||||||
|
if (mounted && p.snapshot_id === snapshotIdRef.current) {
|
||||||
setProgress(p);
|
setProgress(p);
|
||||||
}
|
}
|
||||||
|
}).then((fn) => {
|
||||||
|
if (mounted) {
|
||||||
|
unlisten = fn;
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
unlistenPromise.then((unlisten) => unlisten());
|
mounted = false;
|
||||||
|
unlisten?.();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const mutationRef = useRef(mutation);
|
const mutationRef = useRef(mutation);
|
||||||
mutationRef.current = mutation;
|
useEffect(() => {
|
||||||
|
mutationRef.current = mutation;
|
||||||
|
});
|
||||||
|
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
mutationRef.current.reset();
|
mutationRef.current.reset();
|
||||||
|
|||||||
Reference in New Issue
Block a user