Declare your React component tree in JSON
react-from-json
lets you render React
<Foo>
<Bar baz="Hello, world" />
</Foo>
from JSON
{
"type": "Foo",
"props": {
"children": {
"type": "Bar",
"props": {
"baz": "Hello, world"
}
}
}
}
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: "Foo",
props: {
children: {
type: "Bar",
props: {
baz: "Hello, world",
},
},
},
};
const mapping = {
Foo: ({ children }) => (
<div>
<div>{children}</div>
</div>
),
Bar: ({ baz }) => <span>{baz}</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: "Foo",
children: {
_type: "Bar",
baz: "Hello, world",
},
};
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.baz
, and providing a separate components
object.
import React from "react";
import ReactFromJSON from "react-from-json";
const entry = {
type: "Foo",
props: {
baz: {
type: "ComponentLookup",
props: {
componentIndex: 0,
componentType: "Bar",
},
},
},
};
const mapping = {
Foo: ({ baz }) => (
<div>
<div>{baz}</div>
</div>
),
Bar: ({ baz }) => <span>{baz}</span>,
};
const components = {
Bar: [
{
type: "Bar",
props: {
baz: "Hello, world",
},
},
],
};
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 {
Bar: object[];
}
interface Mapping {
Foo: React.ReactNode;
Bar: React.ReactNode;
}
class FooReactFromJSON extends ReactFromJSON<Mapping, Components> {
render(): JSX.Element {
return super.render();
}
}
const Example = () => {
return (
<FooReactFromJSON entry={entry} mapping={mapping} components={components} />
);
};
MIT © Measured Corporation Ltd