Skip to content

Commit 537b3bd

Browse files
author
Ruben van Leeuwen
committed
Final fixes form reset bug
1 parent 8588aec commit 537b3bd

File tree

5 files changed

+90
-68
lines changed

5 files changed

+90
-68
lines changed

frontend/packages/pydantic-forms/src/components/render/RenderForm.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Here we define the outline of the form
77
*/
8-
import React, { useEffect } from 'react';
8+
import React from 'react';
99

1010
import { useTranslations } from 'next-intl';
1111

@@ -26,23 +26,10 @@ const RenderForm = (contextProps: PydanticFormContextProps) => {
2626
isSending,
2727
skipSuccessNotice,
2828
loadingComponent,
29-
rhf,
30-
errorDetails,
31-
formInputData,
3229
} = contextProps;
3330

3431
const { formRenderer, footerRenderer, headerRenderer } = config || {};
3532

36-
useEffect(() => {
37-
if (errorDetails) {
38-
// If we have an array restore the values
39-
const lastValues = [...formInputData].pop();
40-
rhf.reset({
41-
...lastValues,
42-
});
43-
}
44-
}, [errorDetails, formInputData]);
45-
4633
const pydanticFormComponents: PydanticFormComponents =
4734
getPydanticFormComponents(
4835
pydanticFormSchema?.properties || {},

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

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ function PydanticFormContextProvider({
6262
labelProvider,
6363
customDataProvider,
6464
customDataProviderCacheKey,
65-
formStructureMutator,
66-
fieldDetailProvider,
6765
resetButtonAlternative,
6866
allowUntouchedSubmit,
6967
skipSuccessNotice,
@@ -72,27 +70,22 @@ function PydanticFormContextProvider({
7270
cancelButton,
7371
} = config;
7472

75-
const awaitReset = async (payLoad: FieldValues = {}) => {
76-
rhf.reset(payLoad);
77-
await new Promise((resolve) => setTimeout(resolve, 0)); // wait one tick
78-
};
79-
8073
const [formInputHistory, setFormInputHistory] = useState(
8174
new Map<string, object>(),
8275
);
8376
const [formInputData, setFormInputData] = useState<object[]>([]);
8477

8578
const formRef = useRef<string>(formKey);
8679

87-
const updateHistory = async (
88-
formInput: object,
89-
previousSteps: object[],
90-
) => {
91-
const hashOfPreviousSteps = await getHashForArray(previousSteps);
92-
setFormInputHistory((prevState) =>
93-
prevState.set(hashOfPreviousSteps, formInput),
94-
);
95-
};
80+
const updateHistory = useCallback(
81+
async (formInput: object, previousSteps: object[]) => {
82+
const hashOfPreviousSteps = await getHashForArray(previousSteps);
83+
setFormInputHistory((prevState) =>
84+
prevState.set(hashOfPreviousSteps, formInput),
85+
);
86+
},
87+
[],
88+
);
9689

9790
const goToPreviousStep = (formInput: object) => {
9891
setFormInputData((prevState) => {
@@ -122,17 +115,21 @@ function PydanticFormContextProvider({
122115
error,
123116
} = useApiProvider(formKey, formInputData, apiProvider, metaData);
124117

125-
const emptyRawSchema: PydanticFormSchemaRawJson = {
126-
type: PydanticFormFieldType.OBJECT,
127-
properties: {},
128-
};
118+
const emptyRawSchema: PydanticFormSchemaRawJson = useMemo(
119+
() => ({
120+
type: PydanticFormFieldType.OBJECT,
121+
properties: {},
122+
}),
123+
[],
124+
);
125+
129126
const [rawSchema, setRawSchema] =
130127
useState<PydanticFormSchemaRawJson>(emptyRawSchema);
131128
const [hasNext, setHasNext] = useState<boolean>(false);
132129

133130
// extract the JSON schema to a more usable custom schema
134131
const { pydanticFormSchema, isLoading: isParsingSchema } =
135-
usePydanticFormParser(rawSchema, formKey, formLabels?.labels);
132+
usePydanticFormParser(rawSchema, formLabels?.labels);
136133

137134
// build validation rules based on custom schema
138135
const zodSchema = useGetZodValidator(
@@ -164,6 +161,14 @@ function PydanticFormContextProvider({
164161
values: initialData,
165162
});
166163

164+
const awaitReset = useCallback(
165+
async (payLoad: FieldValues = {}) => {
166+
rhf.reset(payLoad);
167+
await new Promise((resolve) => setTimeout(resolve, 0)); // wait one tick
168+
},
169+
[rhf],
170+
);
171+
167172
const addFormInputData = useCallback(
168173
(formInput: object, replaceInsteadOfAdd = false) => {
169174
setFormInputData((currentInputs) => {
@@ -208,7 +213,7 @@ function PydanticFormContextProvider({
208213
awaitReset();
209214
rhf.trigger();
210215
},
211-
[rhf],
216+
[awaitReset, rhf],
212217
);
213218

214219
const resetErrorDetails = useCallback(() => {
@@ -226,7 +231,7 @@ function PydanticFormContextProvider({
226231
setIsFullFilled(false);
227232
setRawSchema(emptyRawSchema);
228233
setHasNext(false);
229-
}, []);
234+
}, [emptyRawSchema]);
230235

231236
const PydanticFormContextState = {
232237
// to prevent an issue where the sending state hangs
@@ -299,7 +304,6 @@ function PydanticFormContextProvider({
299304
// When a formKey changes we reset the form input data
300305
useEffect(() => {
301306
if (formKey !== formRef.current) {
302-
console.log('formchange', formKey, formRef.current);
303307
// When the formKey changes we need to reset the form input data
304308
setFormInputData([]);
305309
setFormInputHistory(new Map<string, object>());
@@ -327,7 +331,45 @@ function PydanticFormContextProvider({
327331

328332
setFormInputHistory(new Map<string, object>());
329333
// eslint-disable-next-line react-hooks/exhaustive-deps
330-
}, [apiResponse, isFullFilled]);
334+
}, [apiResponse, isFullFilled]); // Avoid completing the dependencies array here to avoid unwanted resetFormData calls
335+
336+
// this handles errors throws by the useApiProvider call
337+
// for instance unexpected 500 errors
338+
useEffect(() => {
339+
if (!error) {
340+
return;
341+
}
342+
343+
setErrorDetails({
344+
detail: 'Something unexpected went wrong',
345+
source: [],
346+
mapped: {},
347+
});
348+
}, [error]);
349+
350+
useEffect(() => {
351+
const getLocale = () => {
352+
switch (locale) {
353+
case Locale.enGB:
354+
return z.locales.en();
355+
case Locale.nlNL:
356+
return z.locales.nl();
357+
default:
358+
return z.locales.en();
359+
}
360+
};
361+
362+
z.config(getLocale());
363+
}, [locale]);
364+
365+
useEffect(() => {
366+
getHashForArray(formInputData).then((hash) => {
367+
const currentStepFromHistory = formInputHistory.get(hash);
368+
if (currentStepFromHistory) {
369+
awaitReset(currentStepFromHistory);
370+
}
371+
});
372+
}, [awaitReset, formInputData, formInputHistory, rhf]);
331373

332374
return (
333375
<PydanticFormContext.Provider value={PydanticFormContextState}>

frontend/packages/pydantic-forms/src/core/hooks/useGetZodValidator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const getZodValidationObject = (
104104

105105
validationObject[id] = zodRule ?? z.any();
106106
});
107-
return z.object(validationObject);
107+
return validationObject ? z.object(validationObject) : z.any();
108108
};
109109

110110
export const useGetZodValidator = (

frontend/packages/pydantic-forms/src/core/hooks/usePydanticFormParser.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,8 @@ export const parseProperties = (
147147
};
148148

149149
export const usePydanticFormParser = (
150-
rawJsonSchema: PydanticFormSchemaRawJson | undefined,
150+
rawJsonSchema: PydanticFormSchemaRawJson,
151151
formLabels?: Record<string, string>,
152-
fieldDetailProvider?: PydanticFormsContextConfig['fieldDetailProvider'],
153-
formStructureMutator?: PydanticFormsContextConfig['formStructureMutator'],
154152
): {
155153
pydanticFormSchema: PydanticFormSchema | undefined;
156154
isLoading: boolean;
@@ -175,14 +173,11 @@ export const usePydanticFormParser = (
175173
parsedSchema.properties || {},
176174
parsedSchema.required || [],
177175
formLabels,
178-
fieldDetailProvider,
179176
),
180177
};
181178

182-
return formStructureMutator
183-
? formStructureMutator(pydanticFormSchema)
184-
: pydanticFormSchema;
185-
}, [formStructureMutator, parsedSchema, formLabels, fieldDetailProvider]);
179+
return pydanticFormSchema;
180+
}, [parsedSchema, formLabels]);
186181

187182
return {
188183
pydanticFormSchema,

frontend/packages/pydantic-forms/src/core/hooks/useRefParser.tsx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,38 @@
66
* In the JSON Schema there are references to other places in the object.
77
* After this hook is run with the data those references will be resolved.
88
*/
9-
import useSWR, { SWRConfiguration } from 'swr';
9+
import useSWR from 'swr';
1010

1111
import $RefParser from '@apidevtools/json-schema-ref-parser';
1212

1313
import { PydanticFormSchemaParsed, PydanticFormSchemaRawJson } from '@/types';
1414

1515
export function useRefParser(
1616
id: string,
17-
rawJsonSchema?: PydanticFormSchemaRawJson,
18-
swrConfig?: SWRConfiguration,
17+
rawJsonSchema: PydanticFormSchemaRawJson,
1918
) {
2019
return useSWR<PydanticFormSchemaParsed | undefined>(
2120
[id, rawJsonSchema],
22-
23-
// return val
2421
async ([, source]) => {
25-
try {
26-
if (!source) {
27-
return undefined;
28-
}
29-
const parsedSchema = $RefParser.dereference(source, {
30-
mutateInputSchema: false,
31-
}) as unknown as PydanticFormSchemaParsed;
32-
33-
return parsedSchema;
34-
} catch (error) {
35-
console.error(error);
36-
new Error('Could not parse JSON references');
22+
if (!source) {
23+
return undefined;
3724
}
25+
const parsedSchema = (await $RefParser.dereference(source, {
26+
mutateInputSchema: false,
27+
})) as unknown as PydanticFormSchemaParsed;
28+
return parsedSchema;
3829
},
39-
40-
// swr config
4130
{
42-
...swrConfig,
31+
fallback: {},
32+
33+
// We revalidate to make sure the form updates when we use it a second time
34+
revalidateIfStale: true,
35+
revalidateOnReconnect: false,
36+
revalidateOnFocus: false,
37+
// We want to make sure the correct data is showing so we don't want to prefill with stale data
38+
// we dont use the previous data because of that
39+
keepPreviousData: false,
40+
shouldRetryOnError: false,
4341
},
4442
);
4543
}

0 commit comments

Comments
 (0)