Skip to content

Commit 1c1d0a9

Browse files
erikras-gilfoyle-agenterikras-gilfoyle-agenterikras-dinesh-agentErik Rasmussen
authored
fix: Ensure initial values are reapplied after destroyOnUnregister in StrictMode (#1069)
* fix: Ensure initial values are reapplied after destroyOnUnregister in StrictMode Fixes #1031 Problem: When using destroyOnUnregister with React 18 StrictMode, fields would lose their initial values. This happened because: 1. StrictMode mounts components twice 2. First mount: field registers with initial value 3. StrictMode unmounts: field unregisters, destroyOnUnregister removes it 4. StrictMode remounts: field tries to register again, but final-form thinks initial values haven't changed (they're 'equal'), so doesn't reapply them Solution: Before registering a field, check if it doesn't exist in form state (indicating it was destroyed). If destroyed and we have an initial value, explicitly set the value via form.change() before registering. This ensures initial values are always reapplied when a field re-registers after being destroyed. The fix: - Only affects fields that were destroyed (don't exist in form state) - Checks both field initialValue and form initialValues - Happens before registration, so it's applied correctly - No impact on normal usage (only triggers when field was destroyed) Works with: - React 18 StrictMode + destroyOnUnregister - Normal production builds (no change in behavior) - Initial values from both field config and form initialValues * fix: Handle form-level initialValues in StrictMode re-mount Richard's feedback: The guard check was too narrow. It only checked for field-level initialValue but ignored form-level initialValues. Changed the check from: if (!existingFieldState && initialValue !== undefined) To: if (!existingFieldState) And then check both form-level and field-level initial values inside. This ensures that fields with only form-level initial values (no field-level initialValue) are also correctly restored after StrictMode unmount/remount. * chore: Remove accidentally committed backup file * fix: Handle undefined initialValues in getIn calls TypeScript was correctly flagging that formState.initialValues could be undefined. Added checks before calling getIn to avoid type errors. * fix: Rename unused defaultIsEqual to _defaultIsEqual ESLint requires unused variables to match /^_/u pattern. * fix: Remove unused defaultIsEqual variable entirely Per Erik's feedback - no need to keep it even with underscore prefix. --------- Co-authored-by: erikras-gilfoyle-agent <gilfoyle@openclaw.local> Co-authored-by: erikras-dinesh-agent <dinesh@openclaw.dev> Co-authored-by: Erik Rasmussen <erik@mini.local>
1 parent d3adf45 commit 1c1d0a9

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

src/useField.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ const defaultFormat = (value: any, _name: string) =>
2727
const defaultParse = (value: any, _name: string) =>
2828
value === "" ? undefined : value;
2929

30-
const defaultIsEqual = (a: any, b: any): boolean => a === b;
31-
3230
function useField<
3331
FieldValue = any,
3432
T extends HTMLElement = HTMLElement,
@@ -117,7 +115,7 @@ function useField<
117115
// If no existing state, create a proper initial state
118116
const formState = form.getState();
119117
// Use getIn to support nested field paths like "user.name" or "items[0].id"
120-
const formInitialValue = getIn(formState.initialValues, name);
118+
const formInitialValue = formState.initialValues ? getIn(formState.initialValues, name) : undefined;
121119

122120
// Use Form initialValues if available, otherwise use field initialValue
123121
let initialStateValue = formInitialValue !== undefined ? formInitialValue : initialValue;
@@ -155,6 +153,22 @@ function useField<
155153
});
156154

157155
React.useEffect(() => {
156+
// Check if field state exists in the form before registering
157+
const existingFieldState = form.getFieldState(name as keyof FormValues);
158+
159+
// If field doesn't exist in form state, it means the field was destroyed
160+
// (e.g., by destroyOnUnregister in StrictMode). In this case, we need to
161+
// explicitly set the value before registering to ensure the initial value
162+
// is applied, even if form thinks initialValues haven't changed.
163+
if (!existingFieldState) {
164+
const formState = form.getState();
165+
const formInitialValue = formState.initialValues ? getIn(formState.initialValues, name) : undefined;
166+
const valueToSet = formInitialValue !== undefined ? formInitialValue : initialValue;
167+
if (valueToSet !== undefined) {
168+
form.change(name as keyof FormValues, valueToSet);
169+
}
170+
}
171+
158172
// Register field after the initial render to avoid setState during render
159173
const unregister = register((newState) => {
160174
setState((prevState) => {

0 commit comments

Comments
 (0)