Skip to content

Custom Field onChange not working #3367

Open
@LouaiCoolshop

Description

@LouaiCoolshop

Prerequisites

What theme are you using?

core

Version

4.2.0

Current Behavior

In my react app, I have a form with a few fields. Two of them use a custom field. What I'm trying to do is that when the 1st one's value changes, the 2nd one should clear.

To do that, I'm passing all the form's data into the form context, and making the 2nd field check when the 1st field's value changes (using useEffect), and call "onChange(null)".

The problem is that sometimes the 2nd field's value doesn't nullify. It would call "onChange(null)" but the "formData" for it does not update, and the field will stay the same.

But, if I put that "onChange(null)" into a setTimeout for 50ms, it works always.

The custom field (simplified):

function AutoCompleteAsync(props: AutocompleteAsyncFieldProps) { // type extends "FieldProps"
    const {
        id,
        formData,
        onChange,
        customOptions, // [mine] custom options passed
        isDependant, // [mine] custom boolean passed to show if this field depends on another (resets when it changes)
        formContext,
    } = props;

    const [localValue, setLocalValue] = useState<string>('');
    .... other unrelated states ....

    const allFormData = useMemo<Record<string, any>>(
        () => formContext?.allFormData || {},
        [formContext],
    );

    // If this field depends on another field, evaluate the dependance field name and value
    const [dependsOn, dependsOnEntity, dependanceValue] = useMemo<
        [string | null, string | null, string | null]
    >(() => {
        if (isDependant) {
            // "dependsOn" might contain dots (eg "status.key"), so extract "status.key" from allFormData
            const extractedValue: string | null = get(
                allFormData,
                customOptions.asyncData!.dependsOn!,
                null,
            );
            return [
                customOptions.asyncData!.dependsOn!,
                customOptions.asyncData!.dependsOnEntity!,
                extractedValue,
            ];
        }
        return [null, null, null];
    }, [isDependant, customOptions, allFormData]);

    const onValueSelected = useCallback(
        (val: string) => {
                setLocalValue(val);
                onChange(val);
        },
        [onChange],
    );

    useEffect(() => {
        setLocalValue(formData);
    }, [formData]);

    // In case this field depends on another, reset it when the dependent field value changes
    useEffect(() => {
        if (isDependant) {
            // !!! HERE IS THE PROBLEM: setTimeout as workaround to make it work
            setTimeout(() => {
                onChange(null);
            }, 50);
        }
    }, [
        isDependant,
        dependanceValue,
    ]);

    return (
        <Autocomplete
            ...
            value={localValue}
            onChange={(ev, newVal) => {
                setLocalValue(newVal);
                onChange(newVal);
            }}
        />
    );
}

export default AutoCompleteAsync;

I'm certain that the "onChange(null)" is being called when I need it. Even used the debugger and stepped in. But sometimes it doesn't update the field formData to null when I don't have that setTimeout.

Expected Behavior

When I call "onChange(null)", it should always update the formData instead of just sometimes, without needing to use a setTimeout.

Steps To Reproduce

  1. Inside a react app
  2. Initialize a form with 2 custom fields
  3. Pass in all the form's data into the RJSF component's form context
  4. In the second custom field, add a useEffect to the form data's 1st field
  5. In that useEffect, call "onChange(null)" when the 1st field's value changes
  6. The second field will not update to null sometimes.

Environment

- OS: Windows 11 Pro
- Node: 18.0.0
- npm: 8.6.0

Anything else?

No response

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions