Decomposing UI Components
This is the example illustrating complexities of decomposing a UI component into a series of subcomponents that would simultaneously allow to:
- Redefining the appearance of each of the subcomponent
- 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 a TypeScript code for the component and corresponding interfaces, and the index.js
file contains the compiled JavaScript (check tsconfig.json
for compiler settings).
The index.html
page includes a living example for each of the discussed scenarios, with links pointing to external playgrounds to work through the code if needed. View it in your browser.
The following improvements to the code are left as an exercise for the reader:
-
Returning operation status from the
SearchBox.search
method:public search(query: string): Promise<OperationResult>
Where
type OperationResult = | { status: OperationResultStatus.SUCCESS; results: ISearchResult[]; } | { status: OperationResultStatus.INTERRUPTED } | { status: OperationResultStatus.FAIL; error: any; }; export enum OperationResultStatus { SUCCESS = 'success', FAIL = 'fail', INTERRUPTED = 'interrupted' }
-
Make offer list paginated (implying adding pagination parameters to
ICoffeeApi.search
request and response, and dynamically loading new items while scrolling the offer list) -
Make the input string and the search button a separate
ISeachBoxInput
component. Add an ability to cancel the ongoing request. Add a “skeleton” animation to indicate search results are being loading. -
Localize the component, making a locale and a dictionary a part of the
ISearchBox
options. -
Parametrize
context
parameter forOfferListComponent
andOfferPanelComponent
. Make it comprise only events needed by the component, so thatISearchBoxComposer
would be implementingIOfferListComponentContext
andIOfferPanelComponentContext
interfaces. -
Make
options
mutable (expose anoptionChange
event and implementComposers
's reaction to relevant option changes) -
Parametrize markups of components, either by:
- Incapsulating them in some
Layout
entities controlled through options. Create interfaces for each of the layouts. Create aVisualComponent
base class for entities that have a layout and inheritSearchBox
,OfferListComponent
andOfferPanelComponent
from it, or - Rewriting components as React / ReactNative / SwiftUI / Android View component or as a UI component for any other platform of your choice.
- Incapsulating them in some