react
react copied to clipboard
[BUG] <Form /> onChange event triggers infinitely with pre-populated submission data
Environment
Please provide as many details as you can:
- Hosting type
- [ ] Form.io
- [ x ] Local deployment
- Version: "@formio/react": "5.1.1"
- Formio.js version: 4.13.8
- Frontend framework: ReactJS
- Browser: Chrome
- Browser version: Version 95.0.4638.69 (Official Build) (x86_64)
Steps to Reproduce
- Open console inspector,
- select one of radio buttons, or
- click on the "Force Update" button,
- check the console,
- select any datepicker, switch between months, the datepicker is reset due to infinite re-rendering
Expected behavior
- onChange shall only be triggered after submission data is changed
- datepickers should be able to choose the year and month
Observed behavior
If submission and onChange event are put together, the <Form /> creates infinite loop. It re-renders all elements and slows down the performance
Example
If possible, please provide a screenshot, live example (via JSFiddle or similar), and/or example code to help demonstrate the issue.
For code or form JSON, please enclose in a code block:
import React from "react";
import { form_json } from "./form_json";
import { Form } from "@formio/react";
// import { Form } from "react-formio";
class EditForm extends React.Component {
constructor(){
super();
this.state = {
submission: {
"radio": "yes",
"dateTime": "2021-11-10T12:00:00+13:00"
},
};
}
onSubmissionChange(submission){
console.log('changed', submission);
this.setState({
submission: submission.data,
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="col">
{ console.log('render') }
<a className="btn btn-sm btn-primary" onClick={ () => this.forceUpdate() }>Force Update</a>
<Form
form={form_json}
onChange={ submission => this.onSubmissionChange(submission) }
submission={{ data: this.state.submission }}
options={{
noDefaults: false,
}}
/>
</div>
</div>
</div>
);
}
}
export default EditForm;
form.json
export const form_json = {
components: [
{
label: "Radio",
labelPosition: "top",
optionsLabelPosition: "right",
description: "",
tooltip: "",
customClass: "",
tabindex: "",
inline: false,
hidden: false,
hideLabel: false,
autofocus: false,
disabled: false,
tableView: false,
modalEdit: false,
values: [
{ label: "Yes", value: "yes", shortcut: "" },
{ label: "No", value: "no", shortcut: "" }
],
dataType: "",
persistent: true,
protected: false,
dbIndex: false,
encrypted: false,
redrawOn: "",
clearOnHide: true,
customDefaultValue: "",
calculateValue: "",
calculateServer: false,
allowCalculateOverride: false,
validate: {
required: false,
customMessage: "",
custom: "",
customPrivate: false,
json: "",
strictDateValidation: false,
multiple: false,
unique: false
},
errorLabel: "",
key: "radio",
tags: [],
properties: [],
conditional: { show: null, when: null, eq: "", json: "" },
customConditional: "",
logic: [],
attributes: [],
overlay: {
style: "",
page: "",
left: "",
top: "",
width: "",
height: ""
},
type: "radio",
input: true,
placeholder: "",
prefix: "",
suffix: "",
multiple: false,
unique: false,
refreshOn: "",
widget: null,
validateOn: "change",
showCharCount: false,
showWordCount: false,
allowMultipleMasks: false,
inputType: "radio",
fieldSet: false,
id: "eobgfs",
defaultValue: ""
},
{
label: "Date / Time",
labelPosition: "top",
displayInTimezone: "viewer",
useLocaleSettings: false,
allowInput: true,
format: "dd/MM/yyyy hh:mm a",
placeholder: "",
description: "",
tooltip: "",
customClass: "",
tabindex: "",
hidden: false,
hideLabel: false,
autofocus: false,
disabled: false,
tableView: false,
modalEdit: false,
enableDate: true,
enableMinDateInput: false,
datePicker: {
minDate: null,
maxDate: null,
disable: "",
disableFunction: "",
disableWeekends: false,
disableWeekdays: false,
showWeeks: true,
startingDay: 0,
initDate: "",
minMode: "day",
maxMode: "year",
yearRows: 4,
yearColumns: 5
},
enableMaxDateInput: false,
enableTime: true,
timePicker: {
showMeridian: true,
hourStep: 1,
minuteStep: 1,
readonlyInput: false,
mousewheel: true,
arrowkeys: true
},
multiple: false,
defaultValue: "",
defaultDate: "",
customOptions: [],
persistent: true,
protected: false,
dbIndex: false,
encrypted: false,
redrawOn: "",
clearOnHide: true,
customDefaultValue: "",
calculateValue: "",
calculateServer: false,
allowCalculateOverride: false,
validate: {
required: false,
customMessage: "",
custom: "",
customPrivate: false,
json: "",
strictDateValidation: false,
multiple: false,
unique: false
},
unique: false,
validateOn: "change",
errorLabel: "",
key: "dateTime",
tags: [],
properties: [],
conditional: { show: true, when: "radio", eq: "yes", json: "" },
customConditional: "",
logic: [],
attributes: [],
overlay: {
style: "",
page: "",
left: "",
top: "",
width: "",
height: ""
},
type: "datetime",
timezone: "",
input: true,
widget: {
type: "calendar",
displayInTimezone: "viewer",
language: "en",
useLocaleSettings: false,
allowInput: true,
mode: "single",
enableTime: true,
noCalendar: false,
format: "dd/MM/yyyy hh:mm a",
hourIncrement: 1,
minuteIncrement: 1,
time_24hr: false,
minDate: null,
disabledDates: "",
disableWeekends: false,
disableWeekdays: false,
disableFunction: "",
maxDate: null
},
prefix: "",
suffix: "",
refreshOn: "",
showCharCount: false,
showWordCount: false,
allowMultipleMasks: false,
datepickerMode: "day",
id: "e527s4g"
},
{
title: "Panel",
theme: "default",
tooltip: "",
customClass: "",
collapsible: false,
hidden: false,
disabled: false,
tableView: false,
modalEdit: false,
key: "panel",
tags: [],
properties: [],
customConditional: "show = data.radio === 'no'",
conditional: { json: "", show: "", when: "", eq: "" },
logic: [],
attributes: [],
overlay: {
style: "",
page: "",
left: "",
top: "",
width: "",
height: ""
},
type: "panel",
label: "Panel",
breadcrumb: "default",
tabindex: "",
input: false,
components: [
{
label: "Date / Time",
tableView: false,
enableMinDateInput: false,
datePicker: {
disableWeekends: false,
disableWeekdays: false,
showWeeks: true,
startingDay: 0,
initDate: "",
minMode: "day",
maxMode: "year",
yearRows: 4,
yearColumns: 5,
minDate: null,
maxDate: null
},
enableMaxDateInput: false,
key: "dateTime1",
type: "datetime",
input: true,
widget: {
type: "calendar",
displayInTimezone: "viewer",
language: "en",
useLocaleSettings: false,
allowInput: true,
mode: "single",
enableTime: true,
noCalendar: false,
format: "dd/MM/yyyy hh:mm a",
hourIncrement: 1,
minuteIncrement: 1,
time_24hr: false,
minDate: null,
disableWeekends: false,
disableWeekdays: false,
maxDate: null
},
placeholder: "",
prefix: "",
customClass: "",
suffix: "",
multiple: false,
defaultValue: "",
protected: false,
unique: false,
persistent: true,
hidden: false,
clearOnHide: true,
refreshOn: "",
redrawOn: "",
modalEdit: false,
labelPosition: "top",
description: "",
errorLabel: "",
tooltip: "",
hideLabel: false,
tabindex: "",
disabled: false,
autofocus: false,
dbIndex: false,
customDefaultValue: "",
calculateValue: "",
calculateServer: false,
attributes: [],
validateOn: "change",
validate: {
required: false,
custom: "",
customPrivate: false,
strictDateValidation: false,
multiple: false,
unique: false
},
conditional: { show: null, when: null, eq: "" },
overlay: { style: "", left: "", top: "", width: "", height: "" },
allowCalculateOverride: false,
encrypted: false,
showCharCount: false,
showWordCount: false,
properties: [],
allowMultipleMasks: false,
format: "dd/MM/yyyy hh:mm a",
useLocaleSettings: false,
allowInput: true,
enableDate: true,
enableTime: true,
defaultDate: "",
displayInTimezone: "viewer",
timezone: "",
datepickerMode: "day",
timePicker: {
hourStep: 1,
minuteStep: 1,
showMeridian: true,
readonlyInput: false,
mousewheel: true,
arrowkeys: true
},
customOptions: [],
id: "e20l0yo"
}
],
placeholder: "",
prefix: "",
suffix: "",
multiple: false,
defaultValue: null,
protected: false,
unique: false,
persistent: false,
clearOnHide: false,
refreshOn: "",
redrawOn: "",
labelPosition: "top",
description: "",
errorLabel: "",
hideLabel: false,
autofocus: false,
dbIndex: false,
customDefaultValue: "",
calculateValue: "",
calculateServer: false,
widget: null,
validateOn: "change",
validate: {
required: false,
custom: "",
customPrivate: false,
strictDateValidation: false,
multiple: false,
unique: false
},
allowCalculateOverride: false,
encrypted: false,
showCharCount: false,
showWordCount: false,
allowMultipleMasks: false,
tree: false,
id: "eng58x9"
}
]
}