JSONX Manual


Creating new components

“With great power comes great responsibility”. Just because you can create new Class and Function components with JSONX it doesn’t mean you should. Typically, components should be bundled as UMDs and imported as Custom/External components to optimize performance.

1. Function Components

There are two ways to create function components, either using jsonx._jsonxComponents.getReactFunctionComponent or jsonx._jsonxComponents.makeFunctionComponent. makeFunctionComponent is a shortcut to using getReactFunctionComponent. The difference in component creation with makeFunctionComponent is you can just call that function by passing a regular JavaScript function and underneath the hood, that function will be decomposed into the arguments to the getReactFunctionComponent function.

function myComponent(){
  const [count,setCount] = useState() // you can use any react function inside your function
  const exposeprops = {count,setCount}; // you have to define what props you want passed to your rendered component
  return {// you need to return JSONX JSON
    component:'div',
    passprops:true, //set to true so you can pass 'count' and 'setCount' to child elements 
    children: [
      { component:'span', children:'Clicked Count' },
      {
        component:'input',
        props:{ defaultValue:0 },
        thisprops:{ value:['count'], },
      },
      {
        component:'button',
        __dangerouslyBindEvalProps:{
          onClick(count,setCount){
            setCount(count+1);
          },
        },
        children:'Click me'
      }
    ]
  }
}

jsonx._jsonxComponents.makeFunctionComponent(myComponent) // return React Function Component

JSONX exposes the jsonx._jsonxComponents.getReactFunctionComponent function that can you can use to create React Function Components.

export function getReactFunctionComponent(
  reactComponent: JXM_JSON,
  functionBody: string,
  options = {},
): ReactComponentLike

getReactFunctionComponent takes three arguments:

  1. reactComponent which contains the JXM JSON for rendering the Function Component.
  2. functionBody which is a string for the Function component (if you are using hooks or want to expose props from inside of your components, assign the props you want to make available to an exposeprops variable)
  3. options used to customize getReactFunctionComponent.
const hookFunctionComponent = jsonx._jsonxComponents.getReactFunctionComponent(
  //reactComponent
  {
    component:'div',
    passprops:true,
    children:[
      {
        component:'button',
        __dangerouslyBindEvalProps:{
          onClick:function(clicks,set_click){
            set_click(clicks+1);
          },
        },
        thisprops:{
          clicks:['clicks'],
          set_click:['set_click']
        },
        children:'Click Me',
      },
      {
        component:'span',
        children:' Clicks: '
      },
      {
        component:'span',
        thisprops:{
          _children:['clicks'],
        }
      }
    ]
  },
  //functionBody
  `
  const [clicks, set_click] = useState(0);
  const exposeprops = {clicks,set_click};
  `,
  //options
  {
    name:'hookFunctionComponent',
  });

Example Function Components


2. Class Components

JSONX exposes the jsonx._jsonxComponents.getReactClassComponent function that can you can use to create React Class Components. getReactClassComponent uses createReactClass underneath the hood. You can read more about using createReactClass in the React docs section about “React Without ES6”.

export function getReactClassComponent(
  reactComponent = {},
  options = {},
): ReactComponentLike

getReactClassComponent takes two arguments reactComponent which contains the arguments passed to createReactClass and an options argument.

The only required function in the reactComponent parameter object is a render function, the body of the function has to be valid JXM JSON. Each property in the object has two properties a body property whose value is the function body and an arguments property which defines the parameters for the function.

const reactComponent = {
  //
  // Initialization function
  //
  getInitialState:{
    body:'return { status:"not-loaded", name:"jsonx test", customNumber:1, }',
    arguments:[],
  },
  getDefaultProps:{
    body:'return { someProp:1, someOtherProp:2, status:"original status" }',
    arguments:[],
  },
  componentDidMount:{
    body:`console.log('mounted', 'this.props',this.props, 'this.state',this.state)`,
    arguments:[],
  },
  componentWillUnmount:{
    body:`console.log('unmounted',this.props)`,
    arguments:[],
  },
  //
  // State change functions
  //
  shouldComponentUpdate:{
    body:'console.log("should update component",{nextProps,nextState}); return true;',
    arguments:['nextProps', 'nextState']
  },
  componentWillUpdate:{
    body:'console.log("will update component",{nextProps,nextState}); return true;',
    arguments:['nextProps', 'nextState']
  },
  componentDidUpdate:{
    body:'console.log("did update component",{prevProps,prevState}); return true;',
    arguments:['prevProps', 'prevState']
  },
  //
  // Prop change functions
  //
  componentWillReceiveProps: {
    body:'console.log("will recieve props",{nextProps}); return true;',
    arguments:['nextProps']
  },
  //
  // RENDER IS THE ONLY ***REQUIRED*** FUNCTION
  //
  render:{
    body:{
      component:'p',
      props:{
        status:'from inline prop'
      },
      passprops:true,
      children:[
        {
          component:'span',
          children: 'My Custom React Component Status: ',
        },
        {
          component:'span',
          thisprops:{
            children:['status']
          }
        }
      ]
    },
  }
};
const options = {
  name:'MyCustomComponent',
};
const MyCustomComponent = jsonx._jsonxComponents.getReactClassComponent(reactComponent,options);
const JXM = {
  component:'MyCustomComponent',
  props:{
    status:'Amazing',
  }
};
const boundConfig = {
  debug:true, 
  reactComponents:{
    MyCustomComponent,
  }
};


jsonx.jsonxRender.call(boundConfig, {
  jsonx: JXM, 
  querySelector:'#main', });

Console output after mounting

[Log] mounted (4)
"this.props"
{status: "Amazing", children: {}, someProp: 1, someOtherProp: 2}
"this.state"
{status: "not-loaded", name: "jsonx test", customNumber: 1}

Example Class Components


3. Dynamic Components

JSONX has a helper component called DynamicComponent. Using DynamicComponent allows you to create components that load data and render asynchronously.

The typical use case is if you have some kind of dashboard or components that are independently loading data, Dynamic Components are a convenient way to handle dynamic components without Suspense and Lazy Components (they use hooks under the hood).

Once the data is fetched, the jsonx object passed is rendered and the resolved data is available as resourceprops.DynamicComponentData.

const JXM = {
  component: 'DynamicComponent',
  props: {
    useCache: boolean;
    cacheTimeout: number;//milliseconds
    loadingJSONX: jsonx;
    loadingErrorJSONX: jsonx;
    cacheTimeoutFunction: () => void,
    jsonx: jsonx;
    transformFunction: (data: any) => any,
    fetchURL: string;
    fetchOptions: any;
    fetchFunction: (fetchURL: string, fetchOptions: any)=>Promise,
  }
};
const dynamicComponent = jsonx.getReactElementFromJSONX({
  {
    component:'DynamicComponent',
    props:{
      fetchURL:'/path/to/some/data'
      jsonx:{
        component:'p',
        children:'loaded data',
      }
    }
  },
});

Example Dynamic Components

---

4. Form Components

JSONX has a helper component called FormComponent. Using FormComponent allows you to create forms with react-hook-form without needed to add external form libraries.

Form components work by creating a Function Component that uses the useForm hook. You can customize useForm by adding schema validations via Yup or any of the other optional arguments on useForm.

The actual form elements are passed through the formComponent JXM property. By Default FormComponents are wrapped with form onSubmit={handleSubmit(props.onSubmit)} but the default wrapper can be overwritten with the formWrapperComponent.

FormComponents will add an additional reactComponentLibrary called ReactHookForm with the Controller and ErrorMessage components included. All of the methods returned from the useForm hook are bound to the function context on the this.reactHookForm property. This is useful when you need to customize and pass registers, errors and other react-hook-form functionality into your JXM JSON Object.

const JXM = {
  component: 'FormComponent',
  props: {
    hookFormOptions: {},// settings for react-hook-form's useForm hook
    formComponent: jsonx,
    onSubmit:(formdata: any) => any,
    formWrapperComponent: jsonx,
  }
};
const dynamicComponent = jsonx.getReactElementFromJSONX({
  {
    component:'FormComponent',
    props:{
      onSubmit: (data) => { console.log({ submitData: data }) },
      formComponent:{
        component: "input",
        props: { type: "text", name: "username", placeholder: "username" },
        thiscontext:{ ref:['reactHookForm','register'] },
      },
    }
  },
});

Example Form Components


JSONX & JXM Spec

JSONX Manual