Skip to content

Instantly share code, notes, and snippets.

@Nachasic
Last active June 17, 2024 11:02
Show Gist options
  • Save Nachasic/0431415eec47b4bd090a65bade6e8597 to your computer and use it in GitHub Desktop.
Save Nachasic/0431415eec47b4bd090a65bade6e8597 to your computer and use it in GitHub Desktop.
Serialize react to JSON and de-serialize it back with TypeScript
import * as React from 'react';
import { mount } from 'enzyme';
import { serialize, deserialize } from './react-seritalize';
class CustomComponent extends React.Component<any, any> {
render () {
return <div className="CustomComponent" >{this.props.children}</div>
}
}
const INJECTABLE_TAG = (props: any) => <span className="INJECTABLE_TAG">{props.children}</span>;
const MyAwesome = (props: { children: React.ReactNode }) => <span className="FunctionalComponent"></span>;
const testComponent = <div>
This is a test component with some <MyAwesome>inline stuff happening</MyAwesome>
<INJECTABLE_TAG>
Be prepared for awesomness!!!
</INJECTABLE_TAG>
</div>
describe('React serialization tests', () => {
it('should serialize components', () => {
const ser = serialize(testComponent);
const deser = deserialize(ser, {
components: {
[INJECTABLE_TAG.name]: CustomComponent,
[MyAwesome.name]: MyAwesome
}
})
const wrapper = mount(deser)
console.log(wrapper.html())
})
})
/**
* React-Serialize utility re-written in TypeScript
* Originally created by @pravdomil (https://github.com/pravdomil/react-serialize)
*/
import * as React from 'react';
type ObjectType = {
[index: string]: any;
}
type DeserializableComponent = {
type: string;
props: { children: DeserializableComponent[]; } & ObjectType
}
type ReviverOptions = {
type: string | React.ComponentType,
props: { children: DeserializableComponent[] & ObjectType },
key: string | number,
components: { [type: string]: React.ComponentType }
}
type DeserializationOpts = {
components?: { [type: string]: React.ComponentType };
reviver?: (args: ReviverOptions) => ReviverOptions
}
function deserializeElement(element: DeserializableComponent[] | DeserializableComponent | string | null, options: DeserializationOpts = {}, key?: string | number) {
let { components = {}, reviver } = options
if (typeof element !== "object") {
return element
}
if (element === null) {
return element
}
if (element instanceof Array) {
return element.map((el, i) => deserializeElement(el, options, i))
}
let { props } = element;
const elementType = element.type;
if (typeof elementType !== "string") {
throw new Error("Deserialization error: element type must be string")
}
let type = components[elementType] || elementType.toLowerCase()
if (props.children) {
props = { ...props, children: deserializeElement(props.children, options) }
}
if (reviver) {
({ type, props, key, components } = reviver({ type, props, key, components }))
}
return React.createElement(type, { ...props, key })
}
export const serialize = <T extends React.Component | JSX.Element>(component: T) => {
const getName = (value: string | Function) => {
if (typeof value === 'string') {
return value
} else if (typeof value === 'function') {
return value.name
}
return value
}
const replacer = (key: string, value: any) => {
switch (key) {
case "type":
return getName(value);
case "_owner":
case "_store":
case "ref":
case "key":
return
default:
return value
}
}
return JSON.stringify(component, replacer);
}
export const deserialize = <T extends React.ReactElement<any>>(serializedComponent: string, options?: DeserializationOpts): T => {
const componentData = JSON.parse(serializedComponent);
return deserializeElement(componentData, options) as T;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment