React Child Prop Inheritance and Overrides
Inheritance is a powerful feature of React that allows components to share functionality and structure.
Inheritance is a powerful feature of React that allows components to share functionality and structure.
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.
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>
);
};
React Child Inheritance is useful for a number of reasons:
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.
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.