Decomposing UI Components
This example illustrates the complexities of decomposing a UI component into a series of subcomponents that would simultaneously allow:
- Redefining the appearance of each of the subcomponents.
- Introducing new business logic while keeping styling consistent.
- Inheriting the UX of the component while changing both UI and business logic.
The src folder contains TypeScript code for the component and corresponding interfaces, while the index.js file contains the compiled JavaScript (please refer to tsconfig.json for compiler settings).
The index.html page includes a live example for each of the discussed scenarios, with a live code playgrounds for further code exploration. Feel free to view it in your browser.
The following improvements to the code are left as an exercise for the reader:
-
Make all builder functions configurable through the
SearchBoxoptions (instead of subclassing components and overriding builder functions) -
Make a better abstraction of the
SearchBoxComposerinternal state. Make thefindOfferByIdfunction asynchronous -
Make rendering functions asynchronous
-
Refactor
ISearchBoxComposeras a composition of two interfaces: one facade for interacting with aSearchBox, and another for communication with child components. -
Create a separate composer to bridge the gap between
OfferPanelComponentand its buttons. -
Enhance the
SearchBox.searchmethod to return an operation status:public search(query: string): Promise<OperationResult>Where OperationResult is defined as:
type OperationResult = | { status: OperationResultStatus.SUCCESS; results: ISearchResult[]; } | { status: OperationResultStatus.INTERRUPTED } | { status: OperationResultStatus.FAIL; error: any; };With the enum:
export enum OperationResultStatus { SUCCESS = 'success', FAIL = 'fail', INTERRUPTED = 'interrupted' } -
Implement pagination for the offer list (add pagination parameters to
ICoffeeApi.searchrequest and response, and load new items dynamically while scrolling the offer list). -
Create a separate
ISeachBoxInputcomponent for the input string and the search button. Add the ability to cancel ongoing requests and include a "skeleton" animation to indicate that search results are loading. -
Localize the component by making locale and a dictionary part of the
ISearchBoxoptions. -
Make options mutable by exposing an
optionChangeevent and implementing theComposer's reaction to relevant option changes. -
Parameterize all extra options, content fields, actions, and events.
-
Parametrize the markups of components either by:
-
Encapsulating them in Layout entities controlled through options. Create interfaces for each layout and a VisualComponent base class for entities with layouts. Inherit SearchBox, OfferListComponent, and OfferPanelComponent from this base class.
-
Rewriting components as React / ReactNative / SwiftUI / Android View components or as UI components for other platforms of your choice.
-