OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Can not change state from Dialog button onClick event

  • Thread starter Thread starter Ăżiž
  • Start date Start date
Ă

Ăżiž

Guest
I am working on a Next.js app, and in one of the components, I have a DropdownMenu where one of its items launches a DialogAlert (both are Shadcn components). I am trying to control the dialog's open state with setIsDialogOpen, but it only works when there is a synchronous function before it (like the confirm button example). Otherwise, it won't work when I simply call setIsDialogOpen(false) from the cancel button action.

Here is the code to reproduce the problem:

Code:
"use client";
import { useState } from "react";
import {
 AlertDialog,
 AlertDialogAction,
 AlertDialogCancel,
 AlertDialogContent,
 AlertDialogDescription,
 AlertDialogFooter,
 AlertDialogHeader,
 AlertDialogTitle,
 AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import {
 DropdownMenu,
 DropdownMenuContent,
 DropdownMenuItem,
 DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Loader2 } from "lucide-react";

export default function Home() {
 const [isDialogOpen, setIsDialogOpen] = useState(false);
 const [isLoading, setIsLoading] = useState(false);

 const handleCancelDelete = () => {
   setIsDialogOpen(false);
 };

 const handleDelete = async () => {
   setIsLoading(true);
   // Perform your delete operation here
   await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulating an async operation
   setIsLoading(false);
 };

 return (
   <div>
     <DropdownMenu>
       <DropdownMenuTrigger>Dropdown</DropdownMenuTrigger>
       <DropdownMenuContent>
         <DropdownMenuItem>Action</DropdownMenuItem>
         <DropdownMenuItem
           onClick={() => setIsDialogOpen(true)}
           onSelect={(event) => event.preventDefault()}
         >
           <AlertDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
             <AlertDialogTrigger>Delete</AlertDialogTrigger>
             <AlertDialogContent>
               <AlertDialogHeader>
                 <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
               </AlertDialogHeader>
               <AlertDialogFooter>
                 <AlertDialogCancel
                   onClick={() => {
                     alert("onClick works");
                     setIsDialogOpen(false);
                   }}
                 >
                   Cancel
                 </AlertDialogCancel>
                 {isLoading ? (
                   <Loader2 className="animate-spin" />
                 ) : (
                   <AlertDialogAction
                     onClick={async (e) => {
                       e.preventDefault(); // Prevent default action that closes the dialog
                       await handleDelete();
                       setIsDialogOpen(false);
                     }}
                   >
                     Continue
                   </AlertDialogAction>
                 )}
               </AlertDialogFooter>
             </AlertDialogContent>
           </AlertDialog>
         </DropdownMenuItem>
       </DropdownMenuContent>
     </DropdownMenu>
   </div>
 );
}

Here is a CodeSandbox link to reproduce the issue: https://codesandbox.io/p/devbox/cranky-montalcini-4432z5?embed=1&file=/app/page.tsx:38,20

<p>I am working on a Next.js app, and in one of the components, I have a <code>DropdownMenu</code> where one of its items launches a <code>DialogAlert</code> (both are Shadcn components). I am trying to control the dialog's open state with <code>setIsDialogOpen</code>, but it only works when there is a synchronous function before it (like the confirm button example). Otherwise, it won't work when I simply call <code>setIsDialogOpen(false)</code> from the cancel button action.</p>
<p>Here is the code to reproduce the problem:</p>
<pre><code>"use client";
import { useState } from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Loader2 } from "lucide-react";

export default function Home() {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);

const handleCancelDelete = () => {
setIsDialogOpen(false);
};

const handleDelete = async () => {
setIsLoading(true);
// Perform your delete operation here
await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulating an async operation
setIsLoading(false);
};

return (
<div>
<DropdownMenu>
<DropdownMenuTrigger>Dropdown</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Action</DropdownMenuItem>
<DropdownMenuItem
onClick={() => setIsDialogOpen(true)}
onSelect={(event) => event.preventDefault()}
>
<AlertDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<AlertDialogTrigger>Delete</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel
onClick={() => {
alert("onClick works");
setIsDialogOpen(false);
}}
>
Cancel
</AlertDialogCancel>
{isLoading ? (
<Loader2 className="animate-spin" />
) : (
<AlertDialogAction
onClick={async (e) => {
e.preventDefault(); // Prevent default action that closes the dialog
await handleDelete();
setIsDialogOpen(false);
}}
>
Continue
</AlertDialogAction>
)}
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}

</code></pre>
<p>Here is a CodeSandbox link to reproduce the issue: <a href="https://codesandbox.io/p/devbox/cranky-montalcini-4432z5?embed=1&file=/app/page.tsx:38,20" rel="nofollow noreferrer">https://codesandbox.io/p/devbox/cranky-montalcini-4432z5?embed=1&file=/app/page.tsx:38,20</a></p>
 
Top