Performance issue - lag happening on typing
June 12, 2020 at 11:43amPerformance issue - lag happening on typing
June 12, 2020 at 11:43amHi, I'm using JSON forms standalone with React and I have integrated custom renderer with Quill for some of the inputs to be editors. The forms are part of a view in mobile application developed with React + Cordova. The problem I have is that when the form has more than 8-10 inputs the typings appear really slow on the input field kind of a lag happening between the typing on keyboard and the letters showing on the input. This happens only on Android though. From what I have inspected the main cause of the delay is the handleChange on the <JsonForms />. I have tried different workarounds, one was with using the onBlur function on Quill to invoke the handleChange for JsonForms instead on onChange which improved the performance a lot but unfortunately had problems with saving the last typed input and wasn't the option. Do you have any suggestion on how to improve the performance on typing for this kind of scenario and is there going to be any improvements for the onChange function in later versions?
Great feature by the way, really nifty in my situation.
June 12, 2020 at 12:07pm
Hi thanks for your interest in JSON Forms! There are two places where we need to look:
- Whenever data changes JSON Forms will execute the validation on the whole form. For text inputs with fast typers this might lead to slowdowns, depending on how large the form is. This is something we want to fix in the long run by debouncing the input (probably within
handleChange
): Only apply the input, validate and emit an update change once the user stops typing for a short while. It seems you did something similar on your end to improve the performance. When using timeouts in combinations withonChange
instead ofonBlur
you might be able to implement this yourself. - Make sure that JsonForms isn't fed its emitted data object again. This would trigger an expensive re-rendering including validation on each each data change (additionally to the one triggered by
handleChange
). We usually handle this by storing the updated form data within auseRef
.
If you'd like you can post the code on how you handled the debouncing in your code, so we can take a look and check how the problems could be fixed. Of course we would also welcome a contribution if you have time for that ;) If you need more information or have more questions feel free to ask!
Thank you for the response Stefan! I'll try using timeouts in combinations with
onChange
in the Quill component. Also, I'm not using useRef
, maybe that will help too. Here's my implementation of JsonForms:<JsonFormsschema={schema}uischema={uischema}data={this.state.data}renderers={[...materialRenderers,{ tester: tester, renderer: CustomQuill }]}cells={materialCells}onChange={this.handleChange}/>
and the handleChange function in the component where the JsonForms is
handleChange = (value) => { this.setState({ input:
value.data
}); }
this is the handleChange function in the CustomQuill component that is handling the onChange of <ReactQuill />
handleChange = (data) => { const path = this.props.path; this.props.handleChange(path, data); }
The solution with using timeouts in combinations with onChange actually helped to improve the performance for the inputs that are rendered as editors and handled in Quill component. I didn't thought of that before. Thanks!
June 16, 2020 at 12:02pm
This looks fine as the
data
for JsonForms
comes from state.data
while the handleChange
updates state.input
so there is no "data circle" here.September 1, 2020 at 3:18am
Hello, thanks again for creating and supporting this open source project! I am also using the stand-alone jsonforms with React. I am encountering a similar lagging issue when typing really fast. I tried implementing a debounce function to throttle when onChange is called and it appears to help out a bit but still has a noticeable lag when typing really fast. Please see the debounce function below. Is there something else I am missing or implementing incorrectly?
const debounce = (func, wait) => {let timeout;return function executedFunction(...args) {const later = () => {clearTimeout(timeout);func(...args);};clearTimeout(timeout);timeout = setTimeout(later, wait);};};
<JsonFormsschema={schema}uischema={uischema}data={standaloneData}renderers={[...materialRenderers]}cells={materialCells}onChange={denounce(({({ data, errors }) => setStandaloneData(data), 5000)}/>
For additional context, my schema form file is made up of an array of smaller forms. With i each of those smaller forms are a few
oneOf
elements that changes the form dynamically based on what is selected. I am wondering if this might also be the issue? Please let me know if you need any additional info.September 7, 2020 at 8:16am
Hi (avath), the problem here is that the debounce mechanism has to be more tightly integrated with JSON Forms. In your provided example code the updates which are emitted by JSON Forms are debounced, but at that point of time the "slowdown" already happened.
The issue is that each keystroke updates the internal data representation in JSON Forms which again triggers data validation and a render pass. Therefore the debounce has to happen before JSON Forms is internally updated. (jovana-markovska) did this via custom renderers by debouncing the changes before triggering a data update in JSON Forms. Alternatively you could also generalize this by providing your own JsonForms component with a modified JsonFormsStateProvider in which you could wrap the provided
dispatch
and debounce the update actions where appropriate.May 21, 2021 at 5:55am
As I recently linked this question again:
Make sure that JsonForms isn't fed its emitted data object again. This would trigger an expensive re-rendering including validation on each each data change (additionally to the one triggered by handleChange). We usually handle this by storing the updated form data within a useRef.
This is no longer true. JSON Forms >= 2.5 will detect this scenario and abort rerendering. Therefore it's now completely fine (and even recommended) to refeed the data object.
Still we recommend using debouncing text inputs. We're currently thinking about adding this behavior to text or text area inputs by default, but as of right now this is not the case.