Open
Description
Problem
The current data model is hard to reason about, which makes it less portable and harder to build custom renderers on top of. Some concerns:
zones
are weird- The Root component is treated differently to the other components
- DropZones rely on context or render props, which are React-only paradigms, making it hard to implement Multi-framework support #302 and negatively impacting performance
Example of a custom renderers:
- XML string (i.e. to produce React code)
- Non-React outputs
Current data model
{
"content": [
{
"type": "Columns",
"props": {
"id": "Columns-1234"
}
}
],
"root": { "props": { "title": "Page" } },
"zones": {
"Columns-1234:left": [
{
"type": "Heading",
"props": { "title": "Hello, world" }
}
]
}
}
Proposal
react-from-json implements a predictable AST based on, but not tied to, the React tree. It would allow for custom renders and increased portability.
Proposed data model
{
"root": {
"type": "Root",
"props": {
"title": "Page",
"children": [
{
"type": "Columns",
"props": {
"left": [
{
"type": "Heading",
"props": { "title": "Hello, world" }
}
]
}
}
]
}
},
"content": [], // Deprecated, but still supported
"zones": {}, // Part of DropZone API which will be deprecated, but still supported
}
New slot
API
The children
prop in the above will be powered by the slot
field API, which implements a DropZone-like API but as a field. This makes data much more portable, as it's part of the same payload, whilst also taking advantage of the numerous field APIs (defaultProps
, resolveData
, etc).
Current proposal:
const config = {
fields: {
leftColumn: { type: "slot" }
},
defaultProps: {
leftColumn: {} // Unlike DropZones, you can set defaultProps for slots
},
render: ({ leftColumn }) => (
<div>{leftColumn()}</div>
)
}
DropZone's will be deprecated but retained to avoid breaking changes, but user's will be directed to the slot
API instead.
Considerations
- Implement migration using
migrate()
API - Consider how
content
will be deprecated. We could 1) retaincontent
as is indefinitely, 2) retain support for the user's existing payload (i.e. ifcontent
is passed in,content
will be passed out until the user migrates the data usingmigrate()
), or 3) force the user tomigrate()
their data (breaking change). - Plugins modifying the Data payload will not immediately support
slots
orcontent
if moved underroot.props
. Plugins are experimental, so no mitigation necessary. - Consider making the
react-from-json
model a portable standard - Consider how we might solve for detached roots, such as in Rendering Puck components outside of DropZone #196
Blockers
- Improve rendering performance #644, which is changing the underlying state management