react icon indicating copy to clipboard operation
react copied to clipboard

[BUG] <Form /> onChange event triggers infinitely with pre-populated submission data

Open namti opened this issue 4 years ago • 0 comments

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

  1. Open console inspector,
  2. select one of radio buttons, or
  3. click on the "Force Update" button,
  4. check the console,
  5. select any datepicker, switch between months, the datepicker is reset due to infinite re-rendering

Expected behavior

  1. onChange shall only be triggered after submission data is changed
  2. 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"
		}
	]
}

namti avatar Nov 03 '21 02:11 namti