Skip to content

Commit f19195a

Browse files
author
Ruben van Leeuwen
committed
2059: Improves restoring valuse on navigation and errors
1 parent 21bc1f4 commit f19195a

File tree

2 files changed

+53
-45
lines changed

2 files changed

+53
-45
lines changed

frontend/packages/pydantic-forms/src/core/PydanticFormContextProvider.tsx

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
import {
3535
Locale,
3636
PydanticFormContextProps,
37-
PydanticFormFieldDataStorage,
3837
PydanticFormFieldType,
3938
PydanticFormInitialContextProps,
4039
PydanticFormSchemaRawJson,
@@ -163,11 +162,25 @@ function PydanticFormContextProvider({
163162
});
164163

165164
const awaitReset = useCallback(
166-
async (payLoad: FieldValues = {}) => {
167-
reactHookForm.reset(payLoad);
168-
await new Promise((resolve) => setTimeout(resolve, 0)); // wait one tick
165+
async (payLoad?: FieldValues) => {
166+
getHashForArray(formInputData).then(async (hash) => {
167+
let resetPayload = {};
168+
169+
if (payLoad) {
170+
resetPayload = { ...payLoad };
171+
} else {
172+
const currentStepFromHistory = formInputHistory.get(hash);
173+
174+
if (currentStepFromHistory) {
175+
resetPayload = { ...currentStepFromHistory };
176+
}
177+
}
178+
reactHookForm.reset(resetPayload);
179+
await new Promise((resolve) => setTimeout(resolve, 0)); // wait one tick
180+
});
169181
},
170-
[reactHookForm],
182+
183+
[formInputData, formInputHistory, reactHookForm],
171184
);
172185

173186
const addFormInputData = useCallback(
@@ -247,33 +260,37 @@ function PydanticFormContextProvider({
247260
new Map(),
248261
);
249262

250-
/*
251-
A field might load a list of options from a remote source, load some more and do some logic based on the selection
252-
and only store the final selected id in the form submission data. This method allows to store these intermediate
253-
values to be able to restore the field state when navigating back to it or when errors occur.
254-
*/
255-
const pydanticFormFieldDataStorage: PydanticFormFieldDataStorage = {
256-
has: (fieldId: string, key: string | number) => {
257-
if (
258-
fieldDataStorageRef.current &&
259-
fieldDataStorageRef.current.has(fieldId)
260-
) {
261-
const fieldStorage = fieldDataStorageRef.current.get(fieldId);
262-
return fieldStorage?.has(key.toString()) ?? false;
263-
}
264-
return false;
265-
},
266-
get: (fieldId: string, key: string | number) => {
267-
const fieldData = fieldDataStorageRef?.current?.get(fieldId);
268-
return fieldData?.get(key.toString());
269-
},
270-
set: (fieldId: string, key: string | number, value: unknown) => {
271-
fieldDataStorageRef.current.set(
272-
fieldId,
273-
new Map([[key.toString(), value]]),
274-
);
275-
},
276-
};
263+
const fieldDataStorage = useMemo(
264+
() => ({
265+
has: (fieldId: string, key: string | number) => {
266+
if (
267+
fieldDataStorageRef.current &&
268+
fieldDataStorageRef.current.has(fieldId)
269+
) {
270+
const fieldStorage =
271+
fieldDataStorageRef.current.get(fieldId);
272+
return fieldStorage?.has(key.toString()) ?? false;
273+
}
274+
return false;
275+
},
276+
get: (fieldId: string, key: string | number) => {
277+
const fieldData = fieldDataStorageRef?.current?.get(fieldId);
278+
return fieldData?.get(key.toString());
279+
},
280+
set: (fieldId: string, key: string | number, value: unknown) => {
281+
fieldDataStorageRef.current.set(
282+
fieldId,
283+
new Map([[key.toString(), value]]),
284+
);
285+
},
286+
delete: (fieldId: string) => {
287+
if (fieldDataStorageRef.current?.has(fieldId)) {
288+
fieldDataStorageRef.current.delete(fieldId);
289+
}
290+
},
291+
}),
292+
[],
293+
);
277294

278295
const PydanticFormContextState = {
279296
// to prevent an issue where the sending state hangs
@@ -305,7 +322,7 @@ function PydanticFormContextProvider({
305322
formInputData,
306323
hasNext,
307324
initialData,
308-
pydanticFormFieldDataStorage,
325+
fieldDataStorage,
309326
};
310327

311328
// a useeffect for whenever the error response updates
@@ -350,7 +367,7 @@ function PydanticFormContextProvider({
350367
// When the formKey changes we need to reset the form input data
351368
setFormInputData([]);
352369
setFormInputHistory(new Map<string, object>());
353-
awaitReset();
370+
awaitReset({});
354371
formRef.current = formKey;
355372
}
356373
}, [awaitReset, formKey]);
@@ -373,7 +390,6 @@ function PydanticFormContextProvider({
373390
}
374391

375392
setFormInputHistory(new Map<string, object>());
376-
fieldDataStorageRef.current = new Map();
377393
// eslint-disable-next-line react-hooks/exhaustive-deps
378394
}, [apiResponse, isFullFilled]); // Avoid completing the dependencies array here to avoid unwanted resetFormData calls
379395

@@ -406,15 +422,6 @@ function PydanticFormContextProvider({
406422
z.config(getLocale());
407423
}, [locale]);
408424

409-
useEffect(() => {
410-
getHashForArray(formInputData).then((hash) => {
411-
const currentStepFromHistory = formInputHistory.get(hash);
412-
if (currentStepFromHistory) {
413-
awaitReset(currentStepFromHistory);
414-
}
415-
});
416-
}, [awaitReset, formInputData, formInputHistory, reactHookForm]);
417-
418425
return (
419426
<PydanticFormContext.Provider value={PydanticFormContextState}>
420427
{children(PydanticFormContextState)}

frontend/packages/pydantic-forms/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export type PydanticFormFieldDataStorage = {
5151
set: (fieldId: string, key: string | number, value: unknown) => void;
5252
has: (fieldId: string, key: string | number) => boolean;
5353
get: (fieldId: string, key: string) => unknown;
54+
delete: (fieldId: string) => void;
5455
};
5556

5657
export interface PydanticFormContextProps {
@@ -77,7 +78,7 @@ export interface PydanticFormContextProps {
7778
hasNext: boolean;
7879
formInputData: object[];
7980
initialData: FieldValues;
80-
pydanticFormFieldDataStorage: PydanticFormFieldDataStorage;
81+
fieldDataStorage: PydanticFormFieldDataStorage;
8182
}
8283

8384
export enum PydanticFormState {

0 commit comments

Comments
 (0)