fix(CQ-WEB-8): Add React.memo to performance-sensitive components
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Wrap 7 list-item/card components with React.memo to prevent unnecessary re-renders when parent components update but props remain unchanged: - TaskItem (task lists) - EventCard (calendar views) - EntryCard (knowledge base) - WorkspaceCard (workspace list) - TeamCard (team list) - DomainItem (domain list) - ConnectionCard (federation connections) All are pure components rendered inside .map() loops that depend solely on their props for rendering output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import React from "react";
|
||||
import type { Event } from "@mosaic/shared";
|
||||
import { formatTime } from "@/lib/utils/date-format";
|
||||
|
||||
@@ -5,7 +6,9 @@ interface EventCardProps {
|
||||
event: Event;
|
||||
}
|
||||
|
||||
export function EventCard({ event }: EventCardProps): React.JSX.Element {
|
||||
export const EventCard = React.memo(function EventCard({
|
||||
event,
|
||||
}: EventCardProps): React.JSX.Element {
|
||||
return (
|
||||
<div className="bg-white p-3 rounded-lg border-l-4 border-blue-500 shadow-sm hover:shadow-md transition-shadow">
|
||||
<div className="flex justify-between items-start mb-1">
|
||||
@@ -23,4 +26,4 @@ export function EventCard({ event }: EventCardProps): React.JSX.Element {
|
||||
{event.location && <p className="text-xs text-gray-500">📍 {event.location}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import type { Domain } from "@mosaic/shared";
|
||||
|
||||
interface DomainItemProps {
|
||||
@@ -8,7 +9,11 @@ interface DomainItemProps {
|
||||
onDelete?: (domain: Domain) => void;
|
||||
}
|
||||
|
||||
export function DomainItem({ domain, onEdit, onDelete }: DomainItemProps): React.ReactElement {
|
||||
export const DomainItem = React.memo(function DomainItem({
|
||||
domain,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: DomainItemProps): React.ReactElement {
|
||||
return (
|
||||
<div className="border rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div className="flex items-start justify-between">
|
||||
@@ -52,4 +57,4 @@ export function DomainItem({ domain, onEdit, onDelete }: DomainItemProps): React
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Displays a single federation connection with PDA-friendly design
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { FederationConnectionStatus, type ConnectionDetails } from "@/lib/api/federation";
|
||||
|
||||
interface ConnectionCardProps {
|
||||
@@ -50,7 +51,7 @@ function getStatusDisplay(status: FederationConnectionStatus): {
|
||||
}
|
||||
}
|
||||
|
||||
export function ConnectionCard({
|
||||
export const ConnectionCard = React.memo(function ConnectionCard({
|
||||
connection,
|
||||
onAccept,
|
||||
onReject,
|
||||
@@ -149,4 +150,4 @@ export function ConnectionCard({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
import React from "react";
|
||||
import type { KnowledgeEntryWithTags } from "@mosaic/shared";
|
||||
import { EntryStatus } from "@mosaic/shared";
|
||||
import Link from "next/link";
|
||||
@@ -32,7 +33,9 @@ const visibilityIcons = {
|
||||
PUBLIC: <Eye className="w-3 h-3" />,
|
||||
};
|
||||
|
||||
export function EntryCard({ entry }: EntryCardProps): React.JSX.Element {
|
||||
export const EntryCard = React.memo(function EntryCard({
|
||||
entry,
|
||||
}: EntryCardProps): React.JSX.Element {
|
||||
const statusInfo = statusConfig[entry.status];
|
||||
const visibilityIcon = visibilityIcons[entry.visibility];
|
||||
|
||||
@@ -107,4 +110,4 @@ export function EntryCard({ entry }: EntryCardProps): React.JSX.Element {
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
import React from "react";
|
||||
import type { Task } from "@mosaic/shared";
|
||||
import { TaskStatus, TaskPriority } from "@mosaic/shared";
|
||||
import { formatDate, isPastTarget, isApproachingTarget } from "@/lib/utils/date-format";
|
||||
@@ -21,7 +22,7 @@ const priorityLabels: Record<TaskPriority, string> = {
|
||||
[TaskPriority.LOW]: "Low priority",
|
||||
};
|
||||
|
||||
export function TaskItem({ task }: TaskItemProps): React.JSX.Element {
|
||||
export const TaskItem = React.memo(function TaskItem({ task }: TaskItemProps): React.JSX.Element {
|
||||
const statusIcon = statusIcons[task.status];
|
||||
const priorityLabel = priorityLabels[task.priority];
|
||||
|
||||
@@ -61,4 +62,4 @@ export function TaskItem({ task }: TaskItemProps): React.JSX.Element {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from "react";
|
||||
import type { Team } from "@mosaic/shared";
|
||||
import { Card, CardHeader, CardContent } from "@mosaic/ui";
|
||||
import Link from "next/link";
|
||||
@@ -7,7 +8,10 @@ interface TeamCardProps {
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export function TeamCard({ team, workspaceId }: TeamCardProps): React.JSX.Element {
|
||||
export const TeamCard = React.memo(function TeamCard({
|
||||
team,
|
||||
workspaceId,
|
||||
}: TeamCardProps): React.JSX.Element {
|
||||
return (
|
||||
<Link href={`/settings/workspaces/${workspaceId}/teams/${team.id}`}>
|
||||
<Card className="hover:shadow-lg transition-shadow cursor-pointer">
|
||||
@@ -27,4 +31,4 @@ export function TeamCard({ team, workspaceId }: TeamCardProps): React.JSX.Elemen
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from "react";
|
||||
import type { Workspace } from "@mosaic/shared";
|
||||
import { WorkspaceMemberRole } from "@mosaic/shared";
|
||||
import Link from "next/link";
|
||||
@@ -22,7 +23,7 @@ const roleLabels: Record<WorkspaceMemberRole, string> = {
|
||||
[WorkspaceMemberRole.GUEST]: "Guest",
|
||||
};
|
||||
|
||||
export function WorkspaceCard({
|
||||
export const WorkspaceCard = React.memo(function WorkspaceCard({
|
||||
workspace,
|
||||
userRole,
|
||||
memberCount,
|
||||
@@ -58,4 +59,4 @@ export function WorkspaceCard({
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user