Multiple Re-renders
Answered
Donald Louch posted this in #help-forum
Hey I'm not sure if this is the right server to post on! But I'm currently using
I keeping have re render issues on a couple of pages and I can't figure out why? It renders once all good; then goes in a rendering loop.
Here's my code (the next few messages)!
NextJS 15
, Supabase
, Mantine
, Hugeicons
, and other packages to run my website!I keeping have re render issues on a couple of pages and I can't figure out why? It renders once all good; then goes in a rendering loop.
Here's my code (the next few messages)!
Answered by Donald Louch
So the issue did seem like it was from a few incorrect calls within the
CreateNewInvoice
component 🤦🏻♂️ primarily calling an initial value with null
instead of an empty string/""
and just some improper required fields not being called properly!6 Replies
// page.tsx
import { isUserSignedIn, userList, userRole, userData } from "@/app/actions/clerk"
import Invoices from "./Invoices"
import supabase from "@/lib/supabase"
export default async function InvoicesPage() {
const isUser = await isUserSignedIn()
const role = await userRole()
const isAdmin = isUser && role === "admin" ? true : false
const isMod = isUser && role === "moderator" ? true : false
const isStaff = isAdmin || isMod
const { userId } = await userData()
const { data: invoicesData } = isAdmin
? await supabase.from('Invoices').select().order('createdOn', { ascending: false }) as any
: await supabase.from('Invoices').select().match({ client: userId }).order('createdOn', { ascending: false }) as any
const invoicesArray = new Map()
invoicesData.forEach((invoice: any) => {
const invoiceID = invoice.id.split("_")[2]
const count = invoicesData.filter((inv: any) => inv.id.includes(invoiceID)).length - 1
if (!invoicesArray.has(invoiceID) || new Date(invoice.createdOn) > new Date(invoicesArray.get(invoiceID).createdOn)) {
invoicesArray.set(invoiceID, { ...invoice, multiple: count, invoiceID })
}
})
const invoices = Array.from(invoicesArray.values())
const usersList = await userList().then((res) => JSON.parse(JSON.stringify(res)))
return <Invoices isStaff={isStaff} invoices={invoices} usersList={usersList.data} />
}
// ./Invoices
'use client'
import { BreadCrumb } from "@/app/(Components)/BreadCrumbsComponentPortal";
import CreateNewInvoice from "./CreateNewInvoice";
import InvoiceRow from "./InvoiceRow";
import { Alert, Table, Tabs, Title, Text } from "@mantine/core";
import HugeIcon from "@/app/(Components)/HugeIcon";
export default function Invoices({invoices, usersList, isStaff} : {invoices: any, usersList?: any, isStaff: boolean}){
const breadCrumbs = [
{"pageLink": null, "pageName": "Invoices"},
]
return <>
<BreadCrumb breads={breadCrumbs} />
{isStaff && <CreateNewInvoice isStaff={isStaff} invoices={invoices} usersList={usersList} />}
<Title mt="1.5rem" ta="center">Invoices</Title>
{invoices.length === 0 ? <Alert variant="light" color="green" icon={<HugeIcon name="information-circle" variant="twotone"/>} mt="3rem"><Text my="0.5rem" c="white">There currently is no invoices that have been requested!</Text></Alert> : <Table stickyHeader stickyHeaderOffset={60} highlightOnHover borderColor="var(--darkPurple)" highlightOnHoverColor="var(--darkPurpleRGBA)" striped="even" stripedColor="var(--blackRGBA)" p="1rem" style={{boxShadow: "var(--mantine-shadow-bsSMSecondary)", borderRadius: "var(--mantine-radius-md)", overflow: "hidden"}} my="2rem">
<Table.Tbody>
{invoices.map((invoice: any) => (
<InvoiceRow key={invoice.id} invoice={invoice} isStaff={isStaff} />
))}
</Table.Tbody>
</Table>
}
</>
}
Part 1
// ./InvoiceRow
'use client'
...
export default function InvoiceRow({ invoice, isStaff }: { invoice: any, isStaff: boolean }) {
const invoiceID = invoice.invoiceID;
const router = useRouter()
function openProject() {
router.push(`invoice/${invoiceID}`)
}
const currentTime = new Date()
return <>
<Table.Tr key={invoice.id}>
<Table.Td w="40%">
<Stack gap="1rem" m='1rem'>
<Group>
<Badge color="primary" leftSection={<HugeIcon name="grid" variant="twotone" />}>
{invoiceID}
</Badge>
{isStaff && <Badge color="secondary" leftSection={<HugeIcon name="id" />}>
{invoice.client}
</Badge>}
</Group>
<Group>
<Group>
<InvoiceTypeBadge type={invoice.invoiceType} />
{invoice.versionNumber &&
<Badge color="gray">
Version {invoice.versionNumber}
</Badge>
}
</Group>
{invoice.multiple > 0 &&
<Badge color="blue">
{invoice.multiple} Other versions available
</Badge>
}
</Group>
</Stack>
</Table.Td>
<Table.Td w="10%" ta="center">
<Stack gap="0">
<Tooltip label={invoice.createdOn ? moment(invoice.createdOn!).format("MMMM Do, YYYY [at] h:mma") : "Not Listed"}>
<Text fz="sm" fw="600">{invoice.createdOn ? moment(invoice.createdOn!).format("MM-DD-YYYY") : "Not Listed"}</Text>
</Tooltip>
<Text fz="xs" c="dimmed" mt="-1rem">
Created On
</Text>
</Stack>
</Table.Td>
Part 2
// ./InvoiceRow
<Table.Td w="10%" ta="center">
<Stack gap="0">
<Tooltip label={invoice.paidOn ? <DisplayDate source={invoice.paidOn} /> : invoice.dueOn ? <DisplayDate source={invoice.dueOn} /> : "Not Listed"}>
<Text fz="sm" fw="600" c={ !invoice.dueOn ? "white" : currentTime < new Date(invoice.dueOn) ? "green" : invoice.paidOn && new Date(invoice.paidOn) < new Date(invoice.dueOn) ? "green" : "red" }>{invoice.paidOn ? <DisplayDate source={invoice.paidOn} format="MM-DD-YYYY" /> : invoice.dueOn ? <DisplayDate source={invoice.dueOn} format="MM-DD-YYYY" /> : "Not Listed"}</Text>
</Tooltip>
<Text fz="xs" c="dimmed" mt="-1rem">
{invoice.paidOn ? "Paid On" : "Due On"}
</Text>
</Stack>
</Table.Td>
<Table.Td w="10%" ta="center">
<Stack gap="0">
<Text fz="sm" fw="600" c={invoice.owing > 0 ? "red" : "green"}>
<CurrencyFormat amount={invoice.owing} />
</Text>
<Text fz="xs" c="dimmed" mt="-1rem">
Left Owing
</Text>
</Stack>
</Table.Td>
<Table.Td w="15%" ta="right">
<Tooltip label={`This invoice is primarily related to a ${invoice.relatedItem?.type.toLowerCase()}`}>
<Badge color="gray" leftSection={invoice.relatedItem?.type === "Project" ? <HugeIcon name="files-01" /> : invoice.relatedItem?.type === "Task" ? <HugeIcon name="task-01" /> : <HugeIcon name="grid" />}>
{invoice.relatedItem?.id}
</Badge>
</Tooltip>
</Table.Td>
<Table.Td w="12.5%" ta="left">
<InvoiceStatusBadge status={invoice.status} />
</Table.Td>
<Table.Td w="2.5%" ta="center">
<Tooltip label="View Invoice">
<Box><HugeIcon name="view" variant="duotone" clickOption={openProject} /></Box>
</Tooltip>
</Table.Td>
</Table.Tr>
</>
}
@Donald Louch ts
// ./Invoices
'use client'
import { BreadCrumb } from "@/app/(Components)/BreadCrumbsComponentPortal";
import CreateNewInvoice from "./CreateNewInvoice";
import InvoiceRow from "./InvoiceRow";
import { Alert, Table, Tabs, Title, Text } from "@mantine/core";
import HugeIcon from "@/app/(Components)/HugeIcon";
export default function Invoices({invoices, usersList, isStaff} : {invoices: any, usersList?: any, isStaff: boolean}){
const breadCrumbs = [
{"pageLink": null, "pageName": "Invoices"},
]
return <>
<BreadCrumb breads={breadCrumbs} />
{isStaff && <CreateNewInvoice isStaff={isStaff} invoices={invoices} usersList={usersList} />}
<Title mt="1.5rem" ta="center">Invoices</Title>
{invoices.length === 0 ? <Alert variant="light" color="green" icon={<HugeIcon name="information-circle" variant="twotone"/>} mt="3rem"><Text my="0.5rem" c="white">There currently is no invoices that have been requested!</Text></Alert> : <Table stickyHeader stickyHeaderOffset={60} highlightOnHover borderColor="var(--darkPurple)" highlightOnHoverColor="var(--darkPurpleRGBA)" striped="even" stripedColor="var(--blackRGBA)" p="1rem" style={{boxShadow: "var(--mantine-shadow-bsSMSecondary)", borderRadius: "var(--mantine-radius-md)", overflow: "hidden"}} my="2rem">
<Table.Tbody>
{invoices.map((invoice: any) => (
<InvoiceRow key={invoice.id} invoice={invoice} isStaff={isStaff} />
))}
</Table.Tbody>
</Table>
}
</>
}
I have narrowed the issue down (I think)?! I do believe it's my
{isStaff && <CreateNewInvoice isStaff={isStaff} invoices={invoices} usersList={usersList} />}
component?!So the issue did seem like it was from a few incorrect calls within the
CreateNewInvoice
component 🤦🏻♂️ primarily calling an initial value with null
instead of an empty string/""
and just some improper required fields not being called properly!Answer