Skip to content

Commit

Permalink
fix: Removed infinite loop in AltDateWidget
Browse files Browse the repository at this point in the history
Fixes rjsf-team#3516 by removing the infinite loop caused by two `useEffects()` by adding a new state for the `value` and combining the effects into one
- Updated `AltDateWidget` to stash the `value` in state and combining the two `useEffects()` into a single effect
  - The effect will call `onChange()` when the `state` is ready for change AND it causes a different string than the current `value`
  - If the `lastValue` recorded differs from the `value`, then we record the new `value` and set the `state` to it
- Updated the `CHANGELOG.md` accordingly
  • Loading branch information
heath-freenome committed Mar 19, 2023
1 parent 147a6a2 commit 24d75b2
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 14 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ should change the heading of the (upcoming) version to include a major version b
-->

# 5.3.1

## @rjsf/core

- Updated `AltDateWidget` to switch onChange handling of a single field to match the working code in `antd`, fixing [#3516](https://github.com/rjsf-team/react-jsonschema-form/issues/3516)

# 5.3.0

## @rjsf/antd
Expand Down
27 changes: 13 additions & 14 deletions packages/core/src/components/widgets/AltDateWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MouseEvent, useCallback, useEffect, useReducer } from 'react';
import { MouseEvent, useCallback, useEffect, useReducer, useState } from 'react';
import {
ariaDescribedByIds,
parseDateString,
Expand Down Expand Up @@ -115,22 +115,22 @@ function AltDateWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
value,
}: WidgetProps<T, S, F>) {
const { translateString } = registry;
const [lastValue, setLastValue] = useState(value);
const [state, setState] = useReducer((state: DateObject, action: Partial<DateObject>) => {
return { ...state, ...action };
}, parseDateString(value, time));

useEffect(() => {
if (value && value !== toDateString(state, time)) {
const stateValue = toDateString(state, time);
if (readyForChange(state) && stateValue !== value) {
// The user changed the date to a new valid data via the comboboxes, so call onChange
onChange(stateValue);
} else if (lastValue !== value) {
// We got a new value in the props
setLastValue(value);
setState(parseDateString(value, time));
}
}, [value, state, time]);

useEffect(() => {
if (readyForChange(state)) {
// Only propagate to parent state if we have a complete date{time}
onChange(toDateString(state, time));
}
}, [state, time, onChange]);
}, [time, value, onChange, state, lastValue]);

const handleChange = useCallback((property: keyof DateObject, value: string) => {
setState({ [property]: value });
Expand All @@ -142,8 +142,8 @@ function AltDateWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
if (disabled || readonly) {
return;
}
const nowDateObj = parseDateString(new Date().toJSON(), time);
setState(nowDateObj);
const nextState = parseDateString(new Date().toJSON(), time);
onChange(toDateString(nextState, time));
},
[disabled, readonly, time]
);
Expand All @@ -154,10 +154,9 @@ function AltDateWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
if (disabled || readonly) {
return;
}
setState(parseDateString('', time));
onChange(undefined);
},
[disabled, readonly, time, onChange]
[disabled, readonly, onChange]
);

return (
Expand Down

0 comments on commit 24d75b2

Please sign in to comment.