mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
1a61be49dc
- Kill useJsonStable in CopilotChatConfigurationProvider — useShallowStableRef is now the single stabilization primitive for both messageView props and labels - Harden useShallowStableRef with isPlainObject guard so arrays, Dates, and class instances are never shallow-compared (reference-only for non-plain objects) - Remove redundant stableParentLabels — parentConfig?.labels is already stabilized by the parent provider's own useShallowStableRef - Uninstall ts-deepmerge from react-core dependencies (no longer imported anywhere) - Add unit tests for useShallowStableRef in slots.test.ts (5 tests) - Add changeset (patch) describing the FOR-75 performance fix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1.2 KiB
1.2 KiB
@copilotkit/react-core
| @copilotkit/react-core |
|---|
| patch |
fix: stabilize messageView and labels props to prevent message list re-renders on every keystroke
Passing messageView or labels as inline object props to <CopilotChat /> previously caused all completed assistant messages to re-render on every keystroke due to reference instability. This was especially severe with large message histories (DocuSign: 100+ messages reported 2s→16s send time degradation).
Root causes fixed:
ts-deepmerge.merge()deep-cloned plain objects even from a single source, creating a new reference every render that defeatedMemoizedSlotWrapper's shallow equality check. Replaced with shallow spread +useShallowStableRef.- Inline
labelsobjects created a newmergedLabelscontext value every render, causing alluseCopilotChatConfiguration()consumers across every message to re-render. Fixed by stabilizing withuseShallowStableRefinCopilotChatConfigurationProvider.
The useShallowStableRef hook (added to slots.tsx) is now the single stabilization primitive: it returns the same reference as long as the value is shallowly equal, with an isPlainObject guard to avoid incorrect equality for arrays, Dates, and class instances.