Building reusable components

With functional programming, Typescript generics & Russian doll nesting

Jiechao Lim
Healint-Engineering&data
4 min readNov 9, 2021

--

Gain reusability by nesting a general component within an applied component

I will show how one can create reusable components by walking through a drag-and-drop sorting list created with maximum reusability in mind.

We will build two components, one nested inside another. Do check out the playable demo at the end of this article.

1. Build a general component without any project-specific logic

The general component SortableList contains:

  • sensible default options to configure the drag-and-drop library SortableJS to save the need for (but does not prevent) further configuration from the outside
  • initialization of the the vanilla JS drag-and-drop library SortableJS in useEffect(…)
  • cleanup logic to destroy the old instance of SortableJS in useEffect(…) whenever an updated list of items is passed in
  • callback onSorted to map the rearranged list of items from the DOM (by way of data-* attribute) and pass it up to the applied component AppliedSortableList
  • JSX and CSS for the look and feel that will be reused for sorting any list of items

Notice that the general component SortableList accepts a generic argument Item so the shape of the items being sorted and later handled by the callback onSorted will not be a mystery.

2. Build an applied component from a higher order component

Now put all the project-specific logic in a separate component.

This includes, amongst other things:

  • the interface of the items, BookMetadata, to be sorted
  • a generateUniqueId() function so that even items without any unique property would have a unique identifier attached to it so it can be sorted by SortableList.
  • callback onSorted to pass the rearranged list of items back to the parent component
  • a higher order component createAppliedSortableList(…) which accepts a functor that will remap the list of items to the shape that the general component SortableList needs. This is an inversion of control where the general component SortableList calls the functor given by the applied component AppliedSortableList to execute project-specific code. This is how you will be able to use createAppliedSortableList(…) to reuse SortableList for any list of items of any shape.

Notice that createAppliedSortableList(…) uses partial application, where arguments are passed in in stages.

This allows:

  • the argument for functor to be passed in separately from the props, allowing us to break AppliedSortableList out from SortableList.
  • the inner function to be defined with the assumption that the needed argument, i.e., functor, will be there when invoked.
C3PO, looking at the assembly lines in the droid factory, remarked loudly to R2D2, “Machines making machines! Huh, how perverse.”
Components making components! How perverse and reusable!

Notice that the applied component AppliedSortableList has the interface BookMetadata passed in as generic argument for Item that is then applied to the general component SortableList.

3. Use the applied component

Finally, pass in the list of items listedBooks and state setter function setListedBooks which will receive the rearranged list of items.

Playable Demo

Open in CodeSandbox.

--

--