Higher Order Components
Higher Order Functions
A higher-order function is a function that does at least one of the following:
- takes one or more functions as arguments
- returns a function as its result
What?
A higher-order component is a function that takes a component and returns a new component.
const ComponentWithFeature = withFeature(InternalComponent)
- usually for injecting props in the wrapped component
Why?
- code sharing for class components (and
FC
s) FC
s should always use hooks- HOCs can be composed
withTheme
withTheme
is a HOC that encapsulatesThemeContext
- note the
displayName
convention
import React, { Component, ComponentType, ReactNode } from 'react'
import { ThemeContext, ThemeContextType } from './internal/theme-context'
export interface PropsWithTheme {
theme: ThemeContextType
}
export type PropsWithoutTheme<T> = Omit<T, 'theme'>
export const withTheme = <TProps extends PropsWithTheme>(
WrappedComponent: ComponentType<TProps>,
): ComponentType<PropsWithoutTheme<TProps>> => {
type WithThemeComponentProps = PropsWithoutTheme<TProps>
return class WithThemeComponent extends Component<WithThemeComponentProps> {
static displayName = `withTheme(${
WrappedComponent.displayName || WrappedComponent.name || 'Component'
})`
private themeContextConsumer = (theme: ThemeContextType): ReactNode => {
const props = { ...this.props, theme } as TProps
return <WrappedComponent {...props} />
}
render = (): ReactNode => {
return (
<ThemeContext.Consumer>
{this.themeContextConsumer}
</ThemeContext.Consumer>
)
}
}
}
- injected
theme
prop can be used outside of render (cf.Context.Consumer
)
import React, { Component, FC, ReactNode } from 'react'
import {
DarkTheme,
LightTheme,
PropsWithTheme,
withTheme,
} from './theme-library'
interface InternalThemedParagraphProps extends PropsWithTheme {
children: ReactNode
}
class InternalThemedParagraph extends Component<InternalThemedParagraphProps> {
componentDidMount = () => {
// eslint-disable-next-line no-console
console.log(this.props.theme)
}
render = () => {
const {
theme: {
color: { foreground },
},
children,
} = this.props
return <p style={{ color: foreground }}>{children}</p>
}
}
export const ThemedParagraph = withTheme(InternalThemedParagraph)
interface InternalThemedCardProps extends PropsWithTheme {
children: ReactNode
}
const InternalThemedCard: FC<InternalThemedCardProps> = ({
theme: {
color: { background },
},
children,
}) => {
return <div style={{ backgroundColor: background }}>{children}</div>
}
export const ThemedCard = withTheme(InternalThemedCard)
export default (
<>
<DarkTheme>
<ThemedCard>
<ThemedParagraph>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum
sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat
praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum.
Laborum, molestias temporibus?
</ThemedParagraph>
<ThemedParagraph>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum
sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat
praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum.
Laborum, molestias temporibus?
</ThemedParagraph>
</ThemedCard>
</DarkTheme>
<LightTheme>
<ThemedCard>
<ThemedParagraph>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum
sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat
praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum.
Laborum, molestias temporibus?
</ThemedParagraph>
<ThemedParagraph>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum
sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat
praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum.
Laborum, molestias temporibus?
</ThemedParagraph>
</ThemedCard>
</LightTheme>
</>
)
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum. Laborum, molestias temporibus?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum. Laborum, molestias temporibus?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum. Laborum, molestias temporibus?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta ipsum sapiente ut pariatur. Aliquam suscipit consequuntur similique repellat praesentium eos odit. Ad ipsum voluptatibus natus dignissimos rerum. Laborum, molestias temporibus?