React Child Prop Inheritance and Overrides

Stephen Burke

Inheritance is a powerful feature of React that allows components to share functionality and structure.

Introduction to React Child Inheritance

Inheritance is a powerful feature of React that allows components to share functionality and structure. By using inheritance in component composition, you can create a hierarchy of components that share common functionality and structure, while still allowing for customization and specialization at each level.

In this article, I want to document a pattern that is particularly useful when working with React components. This pattern is known as “React Child Inheritance,” and it allows you to pass down props from a parent component to its children, while still allowing the children to override and extend the props as needed.

What does this look like in practice?

import { Parent, Child } from './components';

const App = () => {
  return (
    <Parent color="red">
      <Child /> {/* Inherits as "red" from the parent! */}
      <Child color="blue" /> {/* Overrides to be "blue"! */}
      <Child />
      <Child />
      <Child />
      <Child />
      <Child />
      <Child color="green" />
      <Child />
      <Child />
    </Parent>
  );
};

Why is this useful?

React Child Inheritance is useful for a number of reasons:

  1. Code Reuse: By using inheritance, you can create a hierarchy of components that share common functionality and structure, reducing duplication and making it easier to maintain and extend your codebase.
  2. Customization: Child components can override and extend the props passed down from their parent, allowing for customization and specialization at each level of the component hierarchy.
  3. Consistency: By using inheritance, you can ensure that components share a consistent structure and behavior, making it easier to reason about and maintain your code.
  4. Predictability: React Child Inheritance provides a clear and predictable way to pass down props from parent to child components, making it easier to understand and debug your code.
  5. Scalability: As your application grows, React Child Inheritance can help you manage the complexity of your component hierarchy and ensure that your code remains maintainable and scalable.

How to use React Child Inheritance

React Child Inheritance can be achieved using a combination of props and the children prop. The children prop is a special prop that is automatically passed to a component by React, and it represents the content that is passed between the opening and closing tags of the component.

We also use the React.cloneElement function to clone the child components and pass down the props from the parent component. This allows the child components to override and extend the props as needed.

Additionally, we want to validate that the children of the parent component are valid. React exposes a validateChild function that can be used to validate the children of a component.

Concrete Example

Let’s consider a simple example to illustrate the concept of React Child Inheritance.

First, lets set up a utility function to validate the children of a component:

import { ReactNode, Children, ReactElement } from 'react';

const getValidChildren = (children: ReactNode) =>
  Children.toArray(children).filter((child) =>
    isValidElement(child),
  ) as ReactElement[]
// static.ts
const colors = ['red', 'blue', 'green'] as const;
// types.ts
type COLORS_TYPE = typeof colors[number];

Suppose we have a Parent component that renders a Child component and passes down a prop called color:

import { PropsWithChildren } from 'react';

// Utils
import { getValidChildren } from './utils';

// Types
import { COLORS_TYPE } from './types';

type ParentProps = PropsWithChildren & HTMLDivElement & {
  color: COLORS_TYPE;
};
const Parent = (props: ParentProps) => {
  const { children, color, ...rest } = props;
  const validChildren = getValidChildren(children);

  return (
    <div {...rest}>
      {validChildren.map((child, idx) => {
        // Check if the child has props.
        const childProps: TableCellProps = child.props || {}

        // Merge the inherited prop with explicitly defined props.
        const mergedProps = {
          ...childProps,
          key: idx,
          color: childProps.alignment ?? color,
        }

        return cloneElement(child, mergedProps)
      })}
    </div>
  );
};

The Parent component passes down the color prop to its children, and the children can override and extend the color prop as needed.

Now, let’s define a Child component that receives the color prop from its parent and uses it to render a colored

// Types
import { COLORS_TYPE } from './types';

type ChildProps = {
  color: COLORS_TYPE;
};

const Child = (props: ChildProps) => {
  const { color } = props;

  return (
    <div style={{ backgroundColor: color }}>
      This is a colored div!
    </div>
  );
};

In this example, the Child component receives the color prop from its parent and uses it to render a colored div.

Now, when we use the Parent component in our application, we can pass down the color prop and render the Child component with the specified color:

import { Parent, Child } from './components';

const App = () => {
  return (
    <Parent color="red">
      <Child /> {/* Inherits as "red" from the parent! */}
      <Child color="blue" /> {/* Overrides to be "blue"! */}
      <Child />
      <Child />
      <Child />
      <Child />
      <Child />
      <Child color="green" />
      <Child />
      <Child />
    </Parent>
  );
};

In this example, the Parent component passes down the color prop to its children, and the children override and extend the color prop as needed. This allows us to create a hierarchy of components that share common functionality and structure, while still allowing for customization and specialization at each level.


Thank you for reading! If you enjoyed this post, feel free to share it with your friends and colleagues. For more insights on web development, technology trends, and digital innovation, stay tuned to this blog.

Prev:

Why Bitcoin? link
Next:

Fullstack TypeScript. Great for code reuse and productivity. link