Skip to content

Commit 27cfa41

Browse files
authored
⚡ Bolt: [performance improvement] Memoize DebouncedInput component (#243)
1 parent 5f21a7d commit 27cfa41

2 files changed

Lines changed: 8 additions & 3 deletions

File tree

.jules/bolt.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@
1313
## 2026-06-20 - AdminPage Re-render Optimization
1414
**Learning:** In the `AdminPage` component, local input state was manually debounced causing the large root component to re-render on every keystroke. This anti-pattern can cause measurable input latency on lower-end devices for complex pages.
1515
**Action:** Use the `DebouncedInput` component for search fields in heavy pages to isolate the fast-changing state and avoid unnecessary full-page renders.
16+
17+
## 2024-06-25 - DebouncedInput Component Memoization
18+
**Learning:** The `DebouncedInput` component was used in several places to prevent excessive parent re-renders while typing. However, because `DebouncedInput` itself was not wrapped in `React.memo()`, it was still re-rendering unnecessarily whenever its parent components re-rendered for reasons unrelated to the input (e.g. other form fields changing, complex page state updates). This unnecessary re-rendering could destroy and recreate its internal debouncing logic and cause extra reconciliation work.
19+
**Action:** When creating utility wrapper components designed to optimize performance (like `DebouncedInput`), ensure the component itself is memoized with `React.memo()` so it fully shields itself from irrelevant parent state updates.

src/components/ui/debounced-input.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { Input } from "@/components/ui/input";
2-
import { useEffect, useState } from "react";
2+
import React, { useEffect, useState } from "react";
33

44
interface DebouncedInputProps extends Omit<React.ComponentProps<typeof Input>, "onChange" | "value"> {
55
value: string;
66
onChange: (value: string) => void;
77
debounce?: number;
88
}
99

10-
export function DebouncedInput({
10+
// ⚡ Bolt: Memoize DebouncedInput to prevent re-renders when parent components update state unrelated to this input
11+
export const DebouncedInput = React.memo(function DebouncedInput({
1112
value,
1213
onChange,
1314
debounce = 300,
@@ -38,4 +39,4 @@ export function DebouncedInput({
3839
onChange={(e) => setLocalValue(e.target.value)}
3940
/>
4041
);
41-
}
42+
});

0 commit comments

Comments
 (0)