I want to give simple loading state using useState hook inside Dialog component.
However, changing the isResultReturned
state from false to be true will make the dialog disappear. And I also see the setIsResultReturned(false)
doesn't change the isResultReturned
state to be false. Did I do something wrong?
I simplify the code to be like below.
// app/page.tsx
import ActionMenu from "./ActionItem";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<ActionMenu name="Test" />
</main>
);
}
// app/ActionItem.tsx
"use client"
import { useState } from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter
} from "@/components/ui/dialog"
import {
Button,
} from "@/components/ui/button"
import { Loader2 } from 'lucide-react';
export default function ActionMenu({ name }: { name: string }) {
const [isResultReturned, setIsResultReturned] = useState(true)
const deleteNoteGroup= () => {
setIsResultReturned(false)
setTimeout(() => {
console.log('wait for 3 seconds')
setIsResultReturned(true)
console.log('check isResultReturned', isResultReturned)
}, 3000)
}
function SharedDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Delete</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Title</DialogTitle>
<DialogDescription>
Description
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="destructive" onClick={deleteNoteGroup}>
{!isResultReturned && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
return (
<SharedDialog />
)
}
As you build a separate function SharedDialog
and returning it, changing in state setIsResultReturned
will rerendering your SharedDialog
that's why it gets closed
Solution:
// app/ActionItem.tsx
"use client"
import { useState } from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter
} from "@/components/ui/dialog"
import {
Button,
} from "@/components/ui/button"
import { Loader2 } from 'lucide-react';
export default function ActionMenu({ name }: { name: string }) {
const [isResultReturned, setIsResultReturned] = useState(true)
const deleteNoteGroup= () => {
setIsResultReturned(false)
setTimeout(() => {
console.log('wait for 3 seconds')
setIsResultReturned(true)
console.log('check isResultReturned', isResultReturned)
}, 3000)
}
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Delete</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Title</DialogTitle>
<DialogDescription>
Description
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="destructive" onClick={deleteNoteGroup}>
{!isResultReturned && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
Changes: Returns a Dialog
directly