Issue with form refreshing on category elements

I have the following react snippet, for some reason when user click on something inside the 2nd and 3rd category tab it causes a refresh and the form to revert to the 1st category tab. I can see it causes the onChange to fire which sets the formData in state but wouldnt expect the page to refresh like it does. Any ideas? Thanks.

interface Props {
  schema: any
  uischema: any
  contentData: any,
  id?: number,
  siteId: number,
  contentTypeId: number
}

export default function JsonForm({schema, uischema, contentData, id, siteId, contentTypeId}: Props) {
    const [formData, setFormData] = useState(contentData ? JSON.parse(contentData) : {});
    const [setButton, setButtonOnClick] = useState(true);

    const renderers = [
      ...materialRenderers,
      // Register custom renderers.
      { tester: FroalaEditorControlTester, renderer: FrolaEditorControl },
      { tester: MediaCaptureControlTester, renderer: MediaCaptureControl },
      { tester: RatingControlTester, renderer: RatingControl },
    ];

  return (
    <>
        <JsonForms
          schema={JSON.parse(schema)}
          uischema={JSON.parse(uischema)}
          data={formData}
          renderers={renderers}
          cells={materialCells}
          onChange={({ errors, data }) => { 
            if(errors != null && errors.length > 0)
            {
              const newErrors = errors.map((error)=>{
                alert(error.message);
              });
              setButtonOnClick(false);
            }
            else
            {
               setButtonOnClick(true);
               setFormData(data);             
            }         
          }}
        />
      
      <div className="float-right flex flex-wrap gap-2">
        <Button id='submit' onClick={() => setButton ? submitContentForm(formData, siteId, contentTypeId, id) : null} type='button'>Save</Button>
      </div>
    </>
  );
}
{
  "type": "Categorization",
  "elements": [
    {
      "type": "Category",
      "label": "Page Content",
      "elements": [
        {
          "type": "VerticalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": "#/properties/content_name"
            }
          ]
        },
        {
          "type": "VerticalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": "#/properties/sections",
              "label": "Content (use the + icon to add more content.)",
              "options": {
                "elementLabelProp": "section_type",
                "showSortButtons": true,
                "detail": {
                  "type": "VerticalLayout",
                  "elements": [
                    {
                      "type": "Control",
                      "label": "Select Content",
                      "scope": "#/properties/section_type"
                    },
                    {
                      "type": "Control",
                      "scope": "#/properties/section_additional_text_fxxxroala",
                      "options": {
                        "multi": true
                      },
                      "rule": {
                        "effect": "SHOW",
                        "condition": {
                          "scope": "#/properties/section_type",
                          "schema": {
                            "enum": [
                              "section_additional_text"
                            ]
                          }
                        }
                      }
                    },
                    {
                      "type": "Control",
                      "scope": "#/properties/section_example_image-media-cxxxapture",
                      "options": {
                        "multi": true
                      },
                      "rule": {
                        "effect": "SHOW",
                        "condition": {
                          "scope": "#/properties/section_type",
                          "schema": {
                            "enum": [
                              "section_example_image"
                            ]
                          }
                        }
                      }
                    },
                    {
                      "type": "Control",
                      "scope": "#/just_all_fields/jaf_additional_text_froala",
                      "options": {
                        "multi": true
                      },
                      "rule": {
                        "effect": "SHOW",
                        "condition": {
                          "scope": "#/properties/section_type",
                          "schema": {
                            "enum": [
                              "section_example_image"
                            ]
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      ]
    },
    {
      "type": "Category",
      "label": "Just all fields",
      "elements": [
        {
          "type": "Group",
          "label": "Something Custom Group header",
          "elements": [
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_string",
              "options": {
                "toggle": true
              }
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_boolean"
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_date"
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_string_enum"
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_rating"
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_additional_text_froala"
            },
            {
              "type": "Control",
              "scope": "#/just_all_fields/jaf_example_image-media-capture"
            }
          ]
        }
      ]
    },
    {
      "type": "Category",
      "label": "Different approach aka comments",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/new-test",
          "options": {
            "elementLabelProp": "selection",
            "detail": {
              "type": "VerticalLayout",
              "elements": [
                {
                  "type": "Control",
                  "label": "Select Content",
                  "scope": "#/properties/selection"
                },
                {
                  "type": "Control",
                  "scope": "#/properties/some-string",
                  "rule": {
                    "effect": "SHOW",
                    "condition": {
                      "scope": "#/properties/selection",
                      "schema": {
                        "enum": [
                          "selection_1"
                        ]
                      }
                    }
                  }
                },
                {
                  "type": "Control",
                  "scope": "#/properties/some-rating",
                  "rule": {
                    "effect": "SHOW",
                    "condition": {
                      "scope": "#/properties/selection",
                      "schema": {
                        "enum": [
                          "selection_2"
                        ]
                      }
                    }
                  }
                },
                {
                  "type": "Control",
                  "scope": "#/properties/some-froala",
                  "rule": {
                    "effect": "SHOW",
                    "condition": {
                      "scope": "#/properties/selection",
                      "schema": {
                        "enum": [
                          "selection_1"
                        ]
                      }
                    }
                  }
                },
                {
                  "type": "Control",
                  "scope": "#/properties/some-media-capture",
                  "rule": {
                    "effect": "SHOW",
                    "condition": {
                      "scope": "#/properties/selection",
                      "schema": {
                        "enum": [
                          "selection_1"
                        ]
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  ]
}

Hi @johno_1000,

The props given to JSON Forms should be stable. In the posted code, every rerender of your JsonForm component (i.e. every change within JSON Forms), will create

  • a new renderers array,
  • a new schema instance
  • a new uischema instance

This will lead to a full rerender of JSON Forms up to a full refresh as all memoization barriers are broken.

Each of these parameters should be placed in a useMemo.

Another issue is that in some code paths of the onChange, setFormData is called while in others it’s not. You should either never call it or always. By only calling it sometimes you will likely experience weird behavior over time (e.g. partial data reset).

1 Like

Thanks Stefan, that seems to have sorted it. Much appreciated.