From f1e718fa00b92ec4913f08bbb7f49e72b6e0de0a Mon Sep 17 00:00:00 2001 From: Matyas Szabo Date: Thu, 19 Dec 2024 10:16:11 +0100 Subject: [PATCH] fix(ui-date-time-input): fix DateTimeInput displaying wrong value of its value is changed in a onChange callback Closes: INSTUI-4406 I could only repropduce it in CodeSandbox, but according to React documentation setState is not deterministic. Backport of PR #1829 from InstUI v10 TEST PLAN: Make a DateTimeInput whose value changes in an onChange listerer on CodeSandbox. It should update properly --- .../ui-date-time-input/src/DateTimeInput/index.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/ui-date-time-input/src/DateTimeInput/index.tsx b/packages/ui-date-time-input/src/DateTimeInput/index.tsx index 081d7149ee..736e5d62bb 100644 --- a/packages/ui-date-time-input/src/DateTimeInput/index.tsx +++ b/packages/ui-date-time-input/src/DateTimeInput/index.tsx @@ -277,7 +277,7 @@ class DateTimeInput extends Component { event.persist() // timeout is needed here because handleDayClick could be called in the same // frame, and it updates calendarSelectedDate which is read in here. - window.setTimeout(() => { + setTimeout(() => { if ((event as React.KeyboardEvent).key === 'Enter') { // user pressed enter, use the selected value in the calendar this.updateStateBasedOnDateInput(this.state.calendarSelectedDate, event) @@ -351,7 +351,15 @@ class DateTimeInput extends Component { newState.message = { text: text, type: 'error' } } if (this.areDifferentDates(this.state.iso, newState.iso)) { - this.props.onChange?.(e, newState.iso?.toISOString()) + if (typeof this.props.onChange === 'function') { + const newDate = newState.iso?.toISOString() + // Timeout is needed here because users might change value in the + // onChange event lister, which might not execute properly because + // the state change is not complete + setTimeout(() => { + this.props.onChange?.(e, newDate) + }, 0) + } } this.setState(newState) } @@ -368,7 +376,7 @@ class DateTimeInput extends Component { // happens on the target before the relatedTarget gets focus. // The timeout gives it a moment for that to happen if (typeof this.props.onBlur === 'function') { - window.setTimeout(() => { + setTimeout(() => { this.props.onBlur?.(e) }, 0) }