Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@

**Learning:** In Next.js/React applications, when grouping items (like schedules or talks) into a `Map` where the values are arrays, using the array spread operator `[...existing, item]` inside a loop (like `forEach` or `map`) causes amortized O(N^2) memory allocations and unnecessary Garbage Collection overhead.
**Action:** Always use `.push()` on the existing array reference if the data structure permits local mutation. For strict ESLint configurations enforcing `no-restricted-syntax`, extract the existing array, push to it, and handle the fallback elegantly (`if (!existing) { map.set(key, [item]); } else { existing.push(item); }`).

## 2025-02-12 — Avoid multiple array `.find()` lookups per render loop

**Learning:** When needing to extract multiple specific properties from an array of objects during a React render (e.g., matching social media link URLs by their `linkType`), using sequential `array.find(item => item.type === "X")` calls per render loop forces redundant O(N) array iterations. Calling this multiple times per render (e.g., 8 times per `SpeakerCard`) is highly inefficient and creates unnecessary CPU overhead.
**Action:** Replace multiple `.find()` lookups with a single O(N) iteration that builds a mapping object (e.g., using `Array.prototype.reduce`), enabling O(1) property access for the remainder of the render loop.
28 changes: 16 additions & 12 deletions components/layout/SpeakerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ interface SpeakerCardProps {
year: number;
}

const extractSocialLink = (links: LinkType[], linkType: string) => {
return links.find((link) => link.linkType === linkType)?.url;
};

export default function SpeakerCard({ name, position, image, links, speakerId, year }: Readonly<SpeakerCardProps>) {
const socialLinks = links.reduce(
(acc, link) => {
acc[link.linkType] = link.url;
return acc;
},
{} as Record<string, string>
);

return (
<motion.div whileHover={{ y: -5, transition: { duration: 0.2 } }} className="speaker-card">
<div className="speaker-image-wrapper">
Expand All @@ -34,23 +38,23 @@ export default function SpeakerCard({ name, position, image, links, speakerId, y
{position && <p className="speaker-position mb-0">{position}</p>}

<div className="speaker-socials">
{extractSocialLink(links, "Twitter") && (
<Link href={extractSocialLink(links, "Twitter")!} className="social-link">
{socialLinks.Twitter && (
<Link href={socialLinks.Twitter} className="social-link">
<i className="fa-brands fa-twitter fa-lg" />
</Link>
)}
{extractSocialLink(links, "LinkedIn") && (
<Link href={extractSocialLink(links, "LinkedIn")!} className="social-link">
{socialLinks.LinkedIn && (
<Link href={socialLinks.LinkedIn} className="social-link">
<i className="fa-brands fa-linkedin-in fa-lg" />
</Link>
)}
{extractSocialLink(links, "Instagram") && (
<Link href={extractSocialLink(links, "Instagram")!} className="social-link">
{socialLinks.Instagram && (
<Link href={socialLinks.Instagram} className="social-link">
<i className="fa-brands fa-instagram fa-lg" />
</Link>
)}
{extractSocialLink(links, "bluesky") && (
<Link href={extractSocialLink(links, "bluesky")!} className="social-link">
{socialLinks.bluesky && (
<Link href={socialLinks.bluesky} className="social-link">
<i className="fa-brands fa-bluesky fa-lg" />
</Link>
)}
Expand Down
Loading