Add fourteen skills from Dimillian/Skills, integrate the merged Snowflake and WordPress updates into the maintainer sync, and refresh registry metadata, attributions, walkthrough notes, and the 8.9.0 release notes while keeping validation warnings within budget.
2.3 KiB
2.3 KiB
Examples
Isolate a ticking timer from a long list
Scenario: A message list re-renders every second because a timer (elapsedMs) lives in the parent component. This causes visible jank on large lists.
Goal: Keep UI identical but limit re-renders to the timer area.
Before (problematic pattern):
function Messages({ items, isThinking, processingStartedAt }) {
const [elapsedMs, setElapsedMs] = useState(0);
useEffect(() => {
if (!isThinking || !processingStartedAt) {
setElapsedMs(0);
return;
}
setElapsedMs(Date.now() - processingStartedAt);
const interval = window.setInterval(() => {
setElapsedMs(Date.now() - processingStartedAt);
}, 1000);
return () => window.clearInterval(interval);
}, [isThinking, processingStartedAt]);
return (
<div>
{items.map((item) => (
<MessageRow key={item.id} item={item} />
))}
<div>{formatDurationMs(elapsedMs)}</div>
</div>
);
}
After (isolated ticking state):
type WorkingIndicatorProps = {
isThinking: boolean;
processingStartedAt?: number | null;
};
const WorkingIndicator = memo(function WorkingIndicator({
isThinking,
processingStartedAt = null,
}: WorkingIndicatorProps) {
const [elapsedMs, setElapsedMs] = useState(0);
useEffect(() => {
if (!isThinking || !processingStartedAt) {
setElapsedMs(0);
return;
}
setElapsedMs(Date.now() - processingStartedAt);
const interval = window.setInterval(() => {
setElapsedMs(Date.now() - processingStartedAt);
}, 1000);
return () => window.clearInterval(interval);
}, [isThinking, processingStartedAt]);
return <div>{formatDurationMs(elapsedMs)}</div>;
});
function Messages({ items, isThinking, processingStartedAt }) {
return (
<div>
{items.map((item) => (
<MessageRow key={item.id} item={item} />
))}
<WorkingIndicator
isThinking={isThinking}
processingStartedAt={processingStartedAt}
/>
</div>
);
}
Why it helps: Only the WorkingIndicator subtree re-renders every second. The list remains stable unless its props change.
Optional follow-ups:
- Wrap
MessageRowinmemoif props are stable. - Use
useCallbackfor handlers passed to rows to avoid re-render churn. - Consider list virtualization if the list is very large.