refactor: introduce WithComponents context provider#3542
Open
refactor: introduce WithComponents context provider#3542
Conversation
- Recreate defaultComponents.ts with all ~100 default component mappings - Fix circular dependency in ComponentsContext by lazy-loading defaults - Remove component override props from Attachment.tsx (use useComponentsContext) - Update tests to use WithComponents wrapper instead of component override props - Fix pre-existing ChannelList filter test (missing countUnread mock)
Contributor
SDK Size
|
Move Chat.LoadingIndicator, Thread.MessageComposer, ThreadList component overrides, ChannelDetails.ChannelDetailsHeader, Poll component overrides, ImageGallery.ImageGalleryVideoControls, and all ThreadsContext component keys to ComponentsContext. - Strip 7 component keys from ThreadsContextValue - Strip ImageGalleryVideoControls from ImageGalleryContextValue - Remove ChannelDetailsHeader prop from ChannelDetailsBottomSheet - Remove component override props from all Poll components - Update tests to use WithComponents wrapper
Migrate all component override props in the SampleApp to use the new WithComponents context provider pattern: - ChannelListScreen: HeaderNetworkDownIndicator, Preview - ChannelScreen: AttachmentPickerSelectionBar, AttachmentPickerContent, MessageLocation, NetworkDownIndicator - ThreadScreen: AttachmentPickerSelectionBar, MessageLocation - NewDirectMessagingScreen: EmptyStateIndicator, SendButton - SharedGroupsScreen: Preview, replace List prop with EmptyStateIndicator override
- Channel screen: MessageLocation and InputButtons moved to WithComponents - Fix InputButtons type to use ComponentOverrides instead of Channel props
- Replace 300-line hand-written ComponentOverrides type with derived type:
`Partial<(typeof import('./defaultComponents'))['DEFAULT_COMPONENTS']>`
- Remove ~110 type imports from ComponentsContext.tsx (now ~55 lines total)
- Add optional component entries to defaultComponents.ts for components
with no default (MessageText, PollContent, Input, etc.)
- Remove remaining component override props from FileAttachment,
StickyHeader, MessageBubble, MessageMenu
- Adding a new overridable component now only requires editing
defaultComponents.ts — the type is auto-derived
Aligns with stream-chat-react's WithComponents API where the prop is named `overrides` instead of `value`.
The shared LoadingIndicator key caused ChannelListView to use the generic text-based indicator instead of the skeleton UI. Split into: - ChannelListLoadingIndicator (default: skeleton UI) - MessageListLoadingIndicator (default: text-based "Loading messages...")
Merge origin/develop into with-component-context. - ChannelScreen/ThreadScreen: kept WithComponents pattern, dropped commented-out props from develop - Channel.tsx: took develop's audioRecordingSendOnComplete=false default - ChannelPreview files: merged specific import style from develop with useComponentsContext from our branch - ChannelSwipableWrapper test: used develop's specific themeContext mock
- Fix WithComponents prop name (value -> overrides) in 6 test files - Move ImageComponent from ChatContext to ComponentsContext with Image default - Move ImageGalleryHeader/Footer/Grid from ImageGalleryContext to ComponentsContext - Move MessageOverlayBackground from OverlayContext to ComponentsContext - Update all consumer components to read from useComponentsContext() - Clean up stale context values in tests
…rences Component overrides are set once at mount and never change dynamically. Remove useMemo dependencies so both the provider value and the hook result are computed once, preventing unnecessary re-renders when integrators pass inline override objects.
- Fix ImageComponent type in Reply.tsx (required, not optional) - Replace React.ComponentType<any> with proper types (ImageProps, ImageGalleryHeaderProps, etc.) to satisfy no-explicit-any lint rule - Add missing ImageProps imports in URLPreview/URLPreviewCompact - Fix prettier formatting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Goal
Replace the prop-drilling of 120+ component overrides with a single
WithComponentscontext provider. This eliminates massive boilerplate acrossChannel,ChannelList, and all consumer components.Before:
After:
🛠 Implementation details
Design principle
All components are read from
useComponentsContext(). All other contexts only provide data + APIs — never components.New
ComponentsContextWithComponentsprovider — nestable, inner overrides win. Usesoverridesprop (aligned withstream-chat-react)useComponentsContext()hook — returns all components with defaults filled inComponentOverridestype — auto-derived fromDEFAULT_COMPONENTSmap (Partial<typeof DEFAULT_COMPONENTS>)defaultComponents.ts— single source of truth for all ~120 default component mappings (lazy-loaded to avoid circular deps)defaultComponents.ts— the type is derived automaticallyWhat changed
MessagesContextValue,InputMessageInputContextValue,ChannelContextValue,ChannelsContextValue,AttachmentPickerContextValue,ThreadsContextValue,ImageGalleryContextValue— these now only carry data + APIsuseCreate*Contexthooks — no longer receive or forward component paramsChannel.tsx— removed ~90 component imports, prop defaults, and forwarding linesChannelList.tsx— removed ~19 component propsuseComponentsContext()for component readsWithComponentsComponentsContext.tsxreduced from ~350 lines to ~55 lines — type is derived from defaults, no manual type maintenanceWithComponentsNet result
<WithComponents overrides={{ ... }}>useComponentsContext()defaultComponents.tsBREAKING CHANGE
<Channel Message={X}>,<ChannelList Preview={X}>,<Thread MessageComposer={X}>, etc. no longer accept component overrides as props. Use<WithComponents overrides={{ Message: X }}>instead.MessagesContextValue,InputMessageInputContextValue,ChannelContextValue,ChannelsContextValue,AttachmentPickerContextValue,ThreadsContextValue,ImageGalleryContextValueno longer include component-type keys. UseuseComponentsContext()to read component overrides.Listprop removed fromChannelList— use customEmptyStateIndicatoroverride or wrapChannelListViewdirectly.LoadingIndicatorprop removed fromChat— use<WithComponents overrides={{ ChatLoadingIndicator: X }}>.🎨 UI Changes
No visual changes — this is a pure structural refactor.
🧪 Testing
yarn build— 0 type errorsyarn lint— passes clean (0 warnings, 0 errors)yarn test:unit— 91/92 suites pass; 1 pre-existing timeout failure inoffline-supportthat also fails ondevelopdefaultComponents.test.tsverifies all default component mappings are defined and optional keys are explicitly listed<WithComponents overrides={...}>wrapper instead of removed component override props☑️ Checklist
developbranch