liveBook · Manning

Generic React component

As explained in React in Depth

A generic React component is a React component whose properties or behavior are parameterized by types that can be specified when the component is used.

A generic React component keeps related prop types in sync without fixing their content type in advance. A paginated list, for example, can accept both employee records and high-score entries while requiring its renderer to accept the same item type as the list. section 5.3 section 6.2

Type a reusable paginator

```tsx interface PaginableItemProps<Type> { item: Type; index: number; } interface PaginableProps<Type> { items: Type[]; Renderer: FC<PaginableItemProps<Type>>; className?: string; } export function Paginable<Type>({ items, Renderer, className }: PaginableProps<Type>) { // Select the current page, then render its items. } ``` The single `Type` parameter links `items` to `Renderer`: an employee renderer belongs with employee items, while a high-score renderer belongs with high-score entries. In the complete paginator, `useState` tracks the current page, `slice` selects four items, and page controls allow each mounted list to navigate independently. section 6.2

Wrapping a generic component can disrupt that relationship. With `forwardRef`, the item type can become `unknown`, so a renderer expecting an employee no longer matches. `memo` presents the same type-preservation problem; do not assume either wrapper retains the original generic signature. section 6.2.1 section 6.2.2

Choose a repair according to how often the pattern occurs:

  • For an occasional forwarded ref, cast the wrapped component to a generic signature that includes `RefAttributes` for the referenced element. The signature is cumbersome, so explain the cast to maintainers. section 6.2.1
  • For `memo`, cast the result to `typeof` the original component; memoization does not otherwise change its type signature. section 6.2.2
  • For many such components, augment React’s `forwardRef` or `memo` type declarations in a `.d.ts` file instead of repeating casts. This changes typings across the application, so use it deliberately. section 6.2.1 section 6.2.2
function PaginableWithoutRef<Type>(    #1
  { items, Renderer, className }: PaginableProps<Type>,
  ref: Ref<HTMLElement>
) {
...
}
const Paginable =
  forwardRef(PaginableWithoutRef) as <Type>(     #2
    p: PaginableProps<Type>    #2
      & RefAttributes<HTMLElement>    #2
) => ReturnType<typeof PaginableWithoutRef>;  #2

The forwarded-ref listing shows the explicit generic cast, including `RefAttributes<HTMLElement>`, that restores the relationship between item and renderer types. section 6.2.1

How React in Depth covers it

How deep it goes
Works through typed props, pagination behavior, and wrapper-induced inference failures, then gives casts and declaration augmentation as repairs.
Examples
Builds an independently navigable employee list and high-score list using the same four-items-per-page component.
What it assumes
Assumes familiarity with React components and TypeScript generics, building on generic functions rather than teaching either from zero.
What you can do after
Build it from scratch with TypeScript props that couple item and renderer types, and repair lost typing after `forwardRef` or `memo`.
How it connects
Connects TypeScript generics with React props, renderer components, pagination, `useState`, `forwardRef`, and `memo`.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of React in Depth. The section links point to the parts of the book it draws on.