@walltowall/react-map-slices-to-components
v0.4.1
Published
React component to map a list of slices to components
Downloads
9
Readme
react-map-slices-to-components
Extends react-map-to-components to suit rendering a list of Prismic Slices. It adds the following features:
- Sensible defaults for
getKey
andgetTypes
. - Override a component mapping by passing a map of curried functions to the
mapOverrides
prop. - Modify the list of slices using a function passed to the
listMiddleware
prop. - Renders a neutral default slice when a mapping is missing. Limited to the development environment.
Install
npm install --save react-map-slices-to-components react-map-to-components
Note that react-map-to-components
is a peer
dependency.
Usage
Default props
Defaults for getKey
and getType
props are configured to work with Prismic.
getKey
: Returns theid
orkey
field of the slice with priority given toid
.getType
: Returns the__typename
field of the slice.
You can easily override them by passing the appropriate prop.
// To override defaults:
<MapSlicesToComponents
getKey={/* custom logic to get key */}
getType={/* custom logic to get type */}
{...props}
/>
Change styling for a specific slice
If you need to change styling for a specific slice, you can utilize the
mapOverrides
prop. This prop allows you to replace the default mapping for any
slice type. When overriding a slice, you receive the original slice component if
you simply want to pass new props to it. If you want to replace the component
completly, the original slice can be ignored.
In the following example, we change the background of a PageBodyImageBlurb
slice to red only if it follows a PageBodyHeroImage
slice. Note that <Comp>
here is the same as <PageBodyImageBlurb>
.
<MapSlicesToComponents
map={/* your slice map */}
mapOverrides={{
PageBodyImageBlurb: Comp => props => {
const overrideProps = {}
if (props.previousType === 'PageBodyHeroImage') overrideProps.bg = 'red'
return <Comp {...props} {...overrideProps} />
},
}}
/>
Notice how we continue to spread props
on the slice in addition to
overrideProps
. This ensures the slice continues to receive all the props it
would have normally received. Since overrideProps
is spread after props
, any
props declared before it will be replaced if present in overrideProps
.
Change data for a specific slice
As shown above, you have access to the slice's props. For example, the
PageBodyImageBlurb
slice from our previous example may take in a heading
prop. If you wanted to manipulate that data before it gets to
PageBodyImageBlurb
, you could override its value.
<MapSlicesToComponents
map={/* your slice map */}
mapOverrides={{
PageBodyImageBlurb: Comp => ({ heading, ...props }) => {
// mockingcase returns a mOcKiNgCaSe version of its input
const newHeading = mockingcase(heading)
return <Comp {...props} heading={newHeading} />
},
}}
/>
We can manipulate any of its props using arbitrary JavaScript. Note that we
spread props
on the returned component to ensure the slice continues to
receive all the props it expects.
Change the list of slices
mapOverrides
allows you to alter the returned component for a slice, but it
does not allow you to determine the order in which it is rendered.
MapSlicesToComponents
takes a listMiddleware
prop that provides
functionality to do just that.
listMiddleware
accepts a function that accepts a list of slices as its only
input and returns a modified version of that list. Modifications could include
whitelisting or blacklisting slice types, reordering slices, or injecting slices
that do not exist anywhere else.
// Removes slices with the GraphQL typename `PrismicPageBodyHeroImage`.
const noPageBodyHeroImage = filter(
slice => slice.__typename !== 'PrismicPageBodyHeroImage',
)
// Flips the order of the slices using Lodash's reverse function.
const reverseSlices = _.reverse
// Adds a SecretSlice to the list as the third element. Since the object is
// passed directly to the slice, you can include any data, including functions.
const addSecretSlice = list => {
const secretSliceData = {
__typename: 'SecretSlice',
id: 'uniqueId',
data: {
handleButtonClick: () => console.log('Functions in data!'),
},
}
list.splice(2, 0, secretSliceData)
return list
}
// Using the listMiddleware prop.
const Page = () => (
<MapSlicesToComponents
list={/* your list */}
listMiddleware={/* middleware function here */}
/>
)
listMiddleware
affects the raw list of slices before it is processed through
mapDataToProps
and map
. listMiddleware
is a low-level API that allows you
to manipulate the data before MapToComponents
processes it.
Providing Global Enhancers
It may be desireable to define global behavior for your mapped props
or
context
objects. In these cases, you can provide the mapDataToPropsEnhancer
and mapDataToContextEnhancer
as props to MapSlicesToComponents
. You can
think of an enhancer as a middleware that runs after your original mapping
function.
An enhancer receives the props
or context
object from the return value of a
slice's mapDataToProps
or mapDataToContext
slice as it's first argument, and
the rest of the data you would normally have in mapDataToProps
or
mapDataToContext
as the second argument.
An enhancer must return the final shape of props
or context
for that slice.
See below for an example.
// Define your global enhancer.
const mapDataToPropsEnhancer = (props, { previousType }) => {
return {
isPreviousHeader: previousType === 'Header'
// Spreading props here allows the original props in the slice
// to have priority over enhancer props.
...props,
}
}
// Use the enhancer.
const Page = () => (
<MapSlicesToComponents
mapDataToPropsEnhancer={mapDataToPropsEnhancer}
/>
)