react-map-to-components
React component to map a list of data to a component based on its type.
This component is especially useful when processing data from an external source with a flexible nature, such as Prismic Slices and WordPress ACF Flexible Content.
npm install --save react-map-to-components
Usage
MapToComponents
takes a list and renders a list of components using a mapping
object. The following example shows the simplest use case.
import React from 'react'
import MapToComponents from 'react-map-to-components'
const list = [
{ id: 1, type: 'HeroBlock', text: 'Text for a Hero component' },
{ id: 2, type: 'CallToActionBlock', text: 'Hey', buttonText: 'Call Me' },
{ id: 3, type: 'FooterBlock', year: 2074 },
]
const App = () => (
<MapToComponents
getKey={(x) => x.id}
getType={(x) => x.type}
list={list}
map={{
HeroBlock: Hero,
CallToActionBlock: CallToAction,
FooterBlock: (props) => <Footer foo="bar" {...props} />,
}}
/>
)
In this example, MapToComponents
will render a list of components using list
by performing the following:
-
For each item in the list, get a key using
getKey
.getKey
should return a unique value for each item in the list, such an an ID or UUID. This value will be used as thekey
prop when rendering the component.Read why this is necessary on React's Lists and Keys guide.
-
For each item in the list, get a type using
getType
.getType
should return a string with a property in themap
object corresponding to a React component. IfgetType
returns a string without a property inmap
, an error will be thrown by default. The default behavior can be overriden if you have a default component to render. -
Using the key and type for each item in the list, a component is rendered for each item. The component used is determined by the type and component key-value mapping in
map
.
Something like the following would be rendered by MapToComponents
:
const App = [
<Hero key={1} />,
<CallToAction key={2} />,
<Footer foo="bar" key={3} />,
]
Providing props to components
In the previous example, notice that an item with type FooterBlock
would
render <Footer>
with the prop foo="bar"
. By creating a new function
component in map
, you can provide default props to your components. This is in
contrast to just passing a reference to a component, as is done with <Hero>
and <CallToAction>
.
By default, no props except key
are passed to the components.
To pass props to the components using data derived from the object in the list,
you can provide a mapDataToProps
prop to MapToComponents
.
mapDataToProps
To pass dynamic props to your components, provide an object to the
mapDataToProps
prop. This prop is similar to map
in that your object should
be a mapping of a list element's type to a function. The function should return
an object of props to provide to the type's component.
<MapToComponents
getKey={(x) => x.id}
getType={(x) => x.type}
list={list}
map={{
HeroBlock: Hero,
CallToActionBlock: CallToAction,
FooterBlock: (props) => <Footer foo="bar" {...props} />,
}}
mapDataToProps={{
HeroBlock: ({ data }) => ({ text: data.text }),
CallToAction: ({ data }) => ({ buttonText: data.buttonText }),
FooterBlock: ({ data }) => ({ year: data.year }),
}}
/>
In the above example, the <Hero>
component would receive a text
prop with
the value data.text
, where data
is the element in the list that maps to the
HeroBlock
type.
Likewise, <CallToAction>
would receive a buttonText
prop, and Footer
would
receive both foo
and year
props.
Each function in mapDataToProps
has access to the current element, data about
the element such as index, and data about sibling elements. See the
mapDataToProps
API for a list of all values available.
mapDataToContext
There may be times where you need to reference data from other elements in the list, such as the previous or next element, that influences the data you pass to your component.
Using just mapDataToProps
, the only way to access a sibiling's derived data
(i.e. data that is dynamically created, not statically available on the element)
is to set it on mapDataToProp
's return object. Since all values returned from
mapDataToProps
are passed to the element's component, this forces the
contextual data to be passed to the component, which may be unwanted.
Data about the next element is also not available yet as the list is mapped synchronously.
Instead, you can provide a mapDataToContext
prop to create contextual data
about an element. This works exactly like mapDataToProps
. The objects returned
from the mapDataToContext
functions are available to the mapDataToProps
functions under the context
properties.
Unlike mapDataToProps
, data returned from mapDataToContext
is not passed to
the component automatically.
Each function in mapDataToProps
has access to the current element, data about
the element such as index, and data about sibling elements. See the
mapDataToContext
API for a list of all values available.
API
MapToComponents
-
getKey
: (Function) Function that returns a unique key for an element in the list. Required. -
getType
: (Function) Function that returns the type for an element in the list. Required. -
list
: (Array): List of data. This can be an array containing mixed types. -
map
: (Object): Object mapping a data type to a React component to be rendered. -
mapDataToProps
: (Object) Object mapping a data type to a function returning props for the component to be rendered. -
mapDataToContext
: (Object) Object mapping a data type to a function returning contextual data for the element. -
meta
: (Any) Arbitrary data that is made available to functions inmapDataToProps
andmapDataToContext
. -
default
: (Component) Component to be rendered if an element type is not defined inmap
. This component always receivestype
as a prop. -
defaultMapDataToProps
: (Function) Function used to determine props for a type not defined inmapDataToProps
. -
defaultMapDataToContext
: (Function) Function used to determine context for a type not defined inmapDataToContext
.
mapDataToProps
Functions in the object passed to mapDataToProps
and defaultMapDataToProps
are provided an object as their only argument with the following properties:
General
-
list
: (Array) List of elements. -
keys
: (Array) List of keys for each element inlist
. -
types
: (Array) List of types for each element inlist
. -
comps
: (Array) List of components for each element inlist
. -
contexts
: (Array) List of context values for each element inlist
. -
map
: (Object) Mapping of types to React components. -
meta
: (Any) Data provided to themeta
prop.
Element
-
data
: (Any) The current element. -
index
: (Integer) The index for the current element. -
context
: (Object) The context for the current element. -
key
: (Any) The key for the current element. -
type
: (String) The type for the current element. -
Comp
: (Component) The component for the current element.
Previous element
-
previousData
: (Any) The previous element. -
previousContext
: (Object) The context for the previous element. -
previousKey
: (Any) The key for the previous element. -
previousType
: (String) The type for the previous element. -
PreviousComp
: (Component) The component for the previous element.
Next element
-
nextData
: (Any) The next element. -
nextContext
: (Object) The context for the next element. -
nextKey
: (Any) The key for the next element. -
nextType
: (String) The type for the next element. -
NextComp
: (Component) The component for the next element.
mapDataToContext
Same signature as mapDataToProps
. All context
properties will be undefined
and should not be used.