Clarifying onChange method & array functionality

I’ve tried using useState and useRef hooks to handle form changes, but don’t think I’m doing it correctly.

//useState
let initialData = generateData(a, b);
const [formData, setFormData] = useState(null);

//useRef
let initialData = generateData(a, b);
const formRef = useRef(initialData);

  <JsonForms
      schema={schema}
      uischema={uiSchema}
      data={initialData}
      renderers={renderers}
     //useState
      onChange={({ _errors, data }) => setFormData(data)}
    //useRef
      onChange={({ _errors, data }) => formRef.current = data}
  />

My issue is with the lag when typing. The forms can be large, and changing a field will even force the form to re-order itself. I saw that debouncing was suggested, but is it absolutely necessary or am I doing something wrong here?

More importantly, I’ve noticed when adding new items to the array, it adds empty objects, instead of an object containing the expected object keys with null values. Is this working as intended, or am I making a mistake?

[original thread by Alec Selinger]

Hi @alec-forms, when you’re on the latest JSON Forms (i.e. 2.5.0) you can simply store the data in the state. Previous versions didn’t handle this case gracefully and slowed down significantly, requiring a useRef approach.

Therefore this is the way to go:

const initialData = generateData(a, b);

const App = () => {
  const [formData, setFormData] = useState(initialData);
  return (<JsonForms
      schema={schema}
      uischema={uiSchema}
      data={formData}
      renderers={renderers}
      onChange={({ _errors, data }) => setFormData(data)}
  />
);
}

If you need to do generateData within your component you might want to use a useMemo to avoid executing generateData with each rerender.

Architecturally the following happens on each change:

  • The internal data is updated

  • A full validation pass is executed

  • A rerendering of each control is triggered

By default we use React.memo on all our components, so most of them do actually not rerender. The validation and rerender pass is usually so fast that there is no noticeable lag for sparsed inputs, e.g. when toggling a check box.

However people type really fast and there can be a noticeable delay as the whole described process is executed by default on each key press. To improve performance for these cases we usually recommend to register a custom renderer for text inputs. Here instead of dispatching a data change for each key press, one can debounce the changes and therefore only dispatch a change when a user stops typing, or every 100ms etc. This avoids slow downs while still displaying immediate feedback. A very simple alternative to debouncing is to only dispatch a change on focus out, with the downside being that the user has to press or something else to see for example validation changes.

[Alec Selinger]

Thanks for your reply @sdirix(sdirix). Appreciate the support at JSONForms.
As for the arrays, if you create a new array and don’t populate the fields, is it expected to return an empty object instead of the expected object keys + null values?

More importantly, I’ve noticed when adding new items to the array, it adds empty objects, instead of an object containing the expected object keys with null values. Is this working as intended, or am I making a mistake?

This works as intended. We only create very simple data, i.e. empty strings, empty objects etc. If you would like default values you can use Ajv for that, see our FAQ.