Can't perform a React state update on a component that hasn't mounted yet?

1 day ago 2
ARTICLE AD BOX

I have a Nextjs application version 16.1.6 with React version 19.2.4.

I am getting the following error:

Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously tries to update the component. Move this work to useEffect instead.

This error was occurring whenever I clicked on the "Impersonate User" button on the page. I made some changes to the code and thought I had fixed the error as I was no longer seeing it but the error is happening occasionally when I navigate to the page and sometimes when I click the "Impersonate User" button.

This is what the useEffect looked like before I made changes,

useEffect(() => { userSearch() .then((data) => { setUsers(data); setLoading(false); }); }, []);

This is what it looks like now,

useEffect(() => { let isMounted = true; userSearch() .then((data) => { if (isMounted) { setUsers(data); setLoading(false); } }); return () => { isMounted = false; }; }, []);

I also moved two async functions that were inside the render function outside.

This is the full code:

"use client"; import { User } from "@/interfaces/odous-api"; import { userSearch } from "@/lib/odous-api"; import { useEffect, useMemo, useState } from "react"; import { impersonateUser, stopImpersonateUser } from "@/lib/permission"; import { useReactTable, getCoreRowModel, flexRender, ColumnDef, CellContext, getFilteredRowModel, getPaginationRowModel, Table as TanStackTable, Column, } from "@tanstack/react-table"; import { CustomPagination } from "@/components/pagination"; import Filter from "@/components/filter"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { TableSkeleton } from "@/components/ui/table-skeleton"; const handleImpersonate = async (userId: string, name: string) => { await impersonateUser(userId, name); window.location.reload(); }; const handleStopImpersonate = async () => { await stopImpersonateUser(); window.location.reload(); }; export default function ImpersonateClient({ impersonateName, }: { impersonateName?: string; }) { const [users, setUsers] = useState<User[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { let isMounted = true; userSearch().then((data) => { if (isMounted) { setUsers(data); setLoading(false); } }); return () => { isMounted = false; }; }, []); const columns = useMemo<ColumnDef<User>[]>( () => [ { accessorKey: "firstName", header: "First Name", }, { accessorKey: "lastName", header: "Last Name", }, { accessorKey: "userName", header: "User Name", }, { header: "Impersonate", cell: (info: CellContext<User, unknown>) => ( <Button className="mb-3" onClick={() => handleImpersonate( info.row.original.id, `${info.row.original.firstName} ${info.row.original.lastName}` ) } > Impersonate </Button> ), }, ], [] ); const table = useReactTable({ data: users, columns, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), }); return ( <div className="w-fit mx-auto mt-4"> {impersonateName && ( <div className="mb-4 p-4 border border-red-500 rounded"> <p className="mb-2">Currently impersonating: {impersonateName}</p> <Button onClick={() => handleStopImpersonate()}> Stop Impersonating </Button> </div> )} <h1 className="mb-4">Impersonate a User</h1> <div className="overflow-hidden"> <Table className="table-auto text-black"> <TableHeader> {table.getHeaderGroups().map((headerGroup) => ( <TableRow key={headerGroup.id}> {headerGroup.headers.map((header) => ( <TableHead key={header.id} className="border-b border-black text-input" > {flexRender( header.column.columnDef.header, header.getContext() )} {header.column.getCanFilter() ? ( <div className="mb-2"> <Filter column={header.column as Column<unknown, unknown>} table={table as TanStackTable<unknown>} /> </div> ) : null} </TableHead> ))} </TableRow> ))} </TableHeader> {loading ? ( <TableBody> {Array.from({ length: 10 }).map((_, index) => ( <TableRow className="border-b border-black" key={index}> <TableSkeleton className="h-4" /> <TableSkeleton className="h-4" /> <TableSkeleton className="h-4" /> <TableSkeleton className="h-4" /> </TableRow> ))} </TableBody> ) : ( <TableBody> {table.getRowModel().rows.map((row) => ( <TableRow key={row.id} className="border-b border-black"> {row.getVisibleCells().map((cell) => ( <TableCell key={cell.id}> {flexRender( cell.column.columnDef.cell, cell.getContext() )} </TableCell> ))} </TableRow> ))} </TableBody> )} </Table> <div className="mt-4"> <CustomPagination table={table as TanStackTable<unknown>} /> </div> </div> </div> ); }

I think the issue has to do with the handImpersonate and handleStopImpersonate functions but I'm not sure what needs to change. The error message says to move the work into the useEffect. I don't know how to set that up to be able to call those functions from the button clicks.

Read Entire Article