Declare your React component tree in JSON
react-from-json
lets you render React
<Burger chain="Wahlburger">
<Patty variant="impossible" />
</Burger>
from JSON
{
"type": "Burger",
"props": {
"chain": "Wahlburger",
"children": {
"type": "Patty",
"props": {
"variant": "impossible"
}
}
}
}
It also supports non-recursive structures.
npm install --save react-from-json
import React from "react";
import ReactFromJSON from "react-from-json";
const entry = {
type: "Burger",
props: {
chain: "Wahlburger",
children: {
type: "Patty",
props: {
variant: "Impossible"
}
}
}
};
const mapping = {
Burger: ({ chain, children }) => (
<div>
<h1>{chain}</h1>
<div>{children}</div>
</div>
),
Patty: ({ variant }) => <span>{variant}</span>
};
const Example = () => {
return <ReactFromJSON entry={entry} mapping={mapping} />;
};
Props passed to your mapped components include
propKey
- name of the prop that rendered your componentpropIndex
- index of your component if using flat trees_type
- thetype
value for your component...props
- the resolved value of yourprops
object, with relevant child nodes rendered as components
If your data doesn't follow the type
| props
shape, react-from-json
makes it easy to map your data on the fly using the mapProp
prop.
import React from "react";
import ReactFromJSON from "react-from-json";
import mapping from "./mapping";
const entryWithDifferentShape = {
_type: "Burger",
chain: "Wahlburger",
children: {
_type: "Patty",
variant: "Impossible"
}
};
const mapProp = prop => {
if (prop._type) {
const { _type, ...props } = prop;
return {
type: _type,
props
};
}
return prop;
};
const Example = () => {
return (
<ReactFromJSON
entry={entryWithDifferentShape}
mapping={mapping}
mapProp={mapProp}
/>
);
};
react-from-json
also supports flat, non-recursive structures via the special <ComponentLookup />
component. This is useful when working with typed systems like GraphQL, and you need to avoid unions.
<ComponentLookup />
simply maps to another component defined in a components
object. If you were using it in React, you would use it like:
<ComponentLookup componentType="Button" componentIndex={0} />
which would look up the Button
component at index 0
in the components
object, resolving to:
<Button id={0}>Hello, World!</Button>
For react-from-json
we use JSON, so we would write this:
{
"type": "ComponentLookup",
"props": {
"componentType": "Button",
"componentIndex": 0
}
}
The
id
here is set by thecomponentIndex
, since we didn't specify one in the JSON. See this comment on IDs for more information.
Here's the same example as above, instead using a <ComponentLookup />
for entry.props.patty
, and providing a separate components
object.
import React from "react";
import ReactFromJSON from "react-from-json";
const entry = {
type: "Burger",
props: {
chain: "Wahlburger",
patty: {
type: "ComponentLookup",
props: {
componentIndex: 0,
componentType: "Patty"
}
}
}
};
const mapping = {
Burger: ({ chain, patty }) => (
<div>
<h1>{chain}</h1>
<div>{patty}</div>
</div>
),
Patty: ({ variant }) => <span>{variant}</span>
};
const components = {
Patty: [
{
type: "Patty",
props: {
variant: "Impossible"
}
}
]
};
const Example = () => {
return (
<ReactFromJSON entry={entry} mapping={mapping} components={components} />
);
};
react-from-json
will map id
from the root of your component JSON to the React component's id
prop. Likewise, if you specify id
under props
, it will use this. If you use the <ComponentLookup />
component, react-from-json
will use the array index as id
unless another id
is specified. Your id
will always take priority.
react-from-json
supports generic types for use with TypeScript.
import { entry, mapping, components } from "./aboveExample";
import ReactFromJSON from "react-from-json";
interface Components {
Patty: object[];
}
interface Mapping {
Burger: React.ReactNode;
Patty: React.ReactNode;
}
class BurgerReactFromJSON extends ReactFromJSON<Mapping, Components> {
render(): JSX.Element {
return super.render();
}
}
const Example = () => {
return (
<BurgerReactFromJSON
entry={entry}
mapping={mapping}
components={components}
/>
);
};
MIT © hydrateio