External changes to formData

Hi Folks,

Apologies if this is dumb question, but I’m more of a backend programmer that a UI / react wiz.

I want to use jsonforms in a system where the form data may have to be updated by something other than during initialisation or the user interacting with the UI. In the case of initialisation the data becomes available async from the UI being started, and in the second case there are other parts of the system that can update the same values that are being changed from the UI.

Playing with the jsonforms-react-seed example I’ve found I can pass the jsonformsData object and setJsonformsData method to my external controller, and have it make changes to the data / call the set method, but:

i) If I make a change to jsonFormsData (with or without calling the set method) the internal data is updated by the components don’t re-render (If I add a categories to the uischema and flick between them I can see the value is updated)

ii) If I call setJsonformsData with a new object each time then the UI does get updated.

So it seem that passing the same object into setJsonformsData isn’t enough to trigger the render (although it does seem to update the internal state), it has to be given a different object each time - is that correct ?

As a side question, I need to pass the setJsonformsData method to my external controller, but I have to do that with App() as that’s where its created - but calling the method also calls App() to be re-executed and hence it re-initialises my controller. I can of course check of that to prevent an infinite loop, but is there some more elegant way to do this (for example is there some kind of “onInit()” callback that can be attached to the Fragment ?

TIA
Phil

Hi @PhilDay,

thanks for your interest in JSON Forms

If I make a change to jsonFormsData (with or without calling the set method) the internal data is updated by the components don’t re-render

The default memoization feature of React works by simple comparison (’===’). When you change the content of jsonformsData but not its “outer shell” React will detect that the object instance of the new jsonformsData is still the same as the old one and therefore will not rerender, assuming there are no changes. JSON Forms uses the same mechanism internally for substructures of the incoming data.

Therefore you should recreate all parent object and array instances whenever you change something within the data. The easiest way, and what we also do internally in JSON Forms, is to use lodash/fp/set which does exactly that for you. Assuming that your data is balanced that is a log(n) operation.

If I call setJsonformsData with a new object each time then the UI does get updated. […] it has to be given a different object each time - is that correct ?

Yes exactly :wink:

As a side question, I need to pass the setJsonformsData method to my external controller, but I have to do that with App() as that’s where its created - but calling the method also calls App() to be re-executed and hence it re-initialises my controller. I can of course check of that to prevent an infinite loop, but is there some more elegant way to do this (for example is there some kind of “onInit()” callback that can be attached to the Fragment ?

Usually you do it the other way around by maintaining the data in the parent of all components which are interested in. So you move the data instead of the setJsonformsData up in the tree. Then you hand down the current data and updateData callbacks to all interested components.

If each rerender reinitializes your controller you should instead place it in a useState and initialize it in the initial useState. If you can only initialize it later then you can use a useEffect with an empty dependency array, which will lead to it being executed only once.

Thanks Stefan - very helpful

1 Like