Compose
import { compose } from 'jynx'
The compose
utility can help improve performance when using several style functions
within a component by combining them into a single function that accepts the collective
arguments of the functions it's been passed.
Usage
To use the compose
utility, include it within your components style argument, and pass
it a list of style functions.
If you're using typescript, define an
intersection
of the selected style functions prop types, then pass this as a generic argument to both
the component and the utility.
/* Import the `compose` utility along with any required functions */
/* and their corresponding props types */
import { compose, color, ColorProps, space, SpaceProps, grid, GridProps } from 'jynx'
/* Define an intersection of all the necessary prop types */
/* (or pass them directly to the component) */
type ComboProps = ColorProps & SpaceProps & GridProps
/* Then create a component using the type and include `compose` within */
/* its style argument, passing to it a list of style functions */
export const Component = styled.div<ComboProps>`
${compose<ComboProps>(color, space, grid)}
`
/* Or using the legacy functional syntax */
export const Component = styled.div<ComboProps>(props => `
${compose<ComboProps>(color, space, grid)}
`)
How it works
The compose
utility works by merging a list of style functions into a single function
that accepts the collective arguments of the functions it's been passed.
This benefits performance by:
- allowing the styles to be parsed concurrently rather than in series
- returning a single style object rather than one for each function
To help visualize this, consider the following:
/* We create a Container and include multiple style functions */
/* within its style argument */
export const Container = styled.div<ColorProps & SpaceProps>`
${color}
${space}
`
/* Then use it in a React component and pass it some */
/* responsive props */
const Layout: React.FC = ({ children }) => (
<Container color={['red', 'green', null, 'blue']} padding={[16, null, 20, 24]}>
{children}
</Container>
)
Here, the props passed to <Container>
are consumed, parsed and returned by their
respective style functions, resulting in the following being rendered in the components
style argument:
export const Container = styled.div<ColorProps & SpaceProps>`
${{
color: 'red',
'@media (min-width: 640px)': {
color: 'green'
},
'@media (min-width: 1280px)': {
color: 'blue'
}
}}
${{
padding: '16px',
'@media (min-width: 960px)': {
padding: '20px'
},
'@media (min-width: 1280px)': {
padding: '24px'
}
}}
`
However, when constructing the same code using the compose
utility, we see the styles
being parsed concurrently and returned as a single object, meaning the resulting style
argument would look something like this:
export const Container = styled.div<ColorProps & SpaceProps>`
${{
color: 'red',
padding: '16px',
'@media (min-width: 640px)': {
color: 'green'
},
'@media (min-width: 960px)': {
padding: '20px'
},
'@media (min-width: 1280px)': {
color: 'blue'
padding: '24px'
}
}}
`
Types
The compose
utility is defined as simple function that takes a deconstructed array of
style functions as arguments and returns a single style function.
A generic parameter T
is used to define the props that can be passed to both the
argument functions and the returned style function.
const compose: <T extends Record<string, any>>(...styleFunctions: StyleFunction<{ [K in keyof T]: T[K] }>[]) => StyleFunction<T>