Skip to content
Open
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
8 changes: 6 additions & 2 deletions src/docs/inbound/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { SwitchCard } from "@/component/v2/switch";
import { clone, create } from "@bufbuild/protobuf";
import { StringValueSchema } from "@bufbuild/protobuf/wkt";
import { Check, ChevronRight, DoorOpen, LogIn, Plus, Save, Settings, Trash } from "lucide-react";
import { FC, useContext, useEffect, useState } from "react";
import { FC, useContext, useEffect, useMemo, useState } from "react";
import useSWR from "swr";
import { FetchProtobuf, ProtoESFetcher, ProtoPath, useProtoSWR } from "../../common/proto";
import Loading, { Error as ErrorDisplay } from "../../component/v2/loading";
Expand Down Expand Up @@ -106,6 +106,10 @@ function InboudComponent() {
const ctx = useContext(GlobalToastContext);
const { data: inbounds, error, isLoading, mutate } = useProtoSWR(inboundService.method.list);

const sortedNames = useMemo(() => {
return [...(inbounds?.names ?? [])].sort((a, b) => a.localeCompare(b));
}, [inbounds?.names]);
Comment on lines +109 to +111

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of useMemo creates a new empty array [] if inbounds.names is empty. If the dependency inbounds?.names changes from one empty array to another (with a different reference), useMemo will re-run and return a new empty array instance. This can cause unnecessary re-renders of components that depend on sortedNames.

To ensure a stable reference for the empty array, you can define it as a constant outside the component and return that constant from useMemo when the names list is empty.

For example:

const EMPTY_NAMES: readonly string[] = [];

// ... inside component
const sortedNames = useMemo(() => {
    const names = inbounds?.names;
    if (!names || names.length === 0) {
        return EMPTY_NAMES;
    }
    return [...names].sort((a, b) => a.localeCompare(b));
}, [inbounds?.names]);

This adheres to the general rule about providing stable references for default/empty objects from useMemo.

References
  1. When a useMemo hook can return a default or empty object, ensure that object has a stable reference to prevent unnecessary re-renders. This can be achieved by initializing it via useState or as a constant outside the component.


const [saving, setSaving] = useState(false);
const [showdata, setShowdata] = useState({ show: false, name: "", new: false });

Expand Down Expand Up @@ -204,7 +208,7 @@ function InboudComponent() {
<CardBody>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{
inbounds.names.sort((a, b) => a.localeCompare(b)).map((name) => (
sortedNames.map((name) => (
<div key={name} className="h-full">
<ListItem
className="h-full justify-between p-4"
Expand Down