reactjstypescriptinputinertiajsreact-state

React Input loses focus after state update


I am trying to build a custom form component. In this I use inertiajs useForm hook to automatically load the data into a state (similar to react-use-form).

But my problem is, that everytime i type a letter (so basically i´m doing a stateupdate), my input field keeps losing its focus.

This is the offical inertiajs documentation: https://inertiajs.com/forms

My form component:

type FormField<T> ={
    name: keyof T;
    label: string;
    type: "text" | "textarea";
    group?: string;
}

interface Props<T extends Record<string, any>> {
    initialData: T
    fields: FormField<T>[]
}

export function Form<T extends Record<string, any>>(props: Props<T>) {
    const { initialData, fields, formLayoutKey } = props;
    const { data, setData, errors, patch } = useForm<T>((initialData ?? {}) as T);

    const onSubmit = (e?: React.FormEvent) => {
        e?.preventDefault();
        console.log(data)
    }

    const renderFieldsByGroup = (group: string) => {
        return fields
            .filter((f) => f.group === group)
            .map((field, index) => {

                // hardcoded .name prop here, but doesnt affect problem
                const value = data.name
                const error = errors[field.name as string];
                const key = `${index}-${field.name}`
                

                switch (field.type) {
                    case 'text':
                        return (
                            <FieldSet key={key} label={field.label} error={error}>
                                {/* Hardcoded "name" here but doesnt affect problem */}
                                <Input
                                    type="text"
                                    placeholder={field.label}
                                    data={value ?? ''}
                                    onChange={e => setData("name", e.target.value)}
                                />
                            </FieldSet>
                        );

                    default:
                        return null;
                }
            });
    };


    return (
        <form onSubmit={onSubmit}>
            <FormLayout>
                <div key="general">   
                     {renderFieldsByGroup("myGroup")}
                </div>
            </FormLayout>
        </form>
    );
}

as you can see, im trying to render my fields based on the field props. My custom input props looks like this:

interface Props {
    type?: string
    placeholder?: string
    classes?: string
    onChange?: (e: any) => void
    data?: string
}

export default function Input(props: Props) {
    const { type = "text", placeholder, classes, onChange, data} = props

    return (
            <input

                type={type ?? "text"}
                placeholder={placeholder}
                className={`${type === "checkbox" ? "checkbox" : "input border"} ${classes}`}
                onChange={onChange}
                value={typeof data === "string" || typeof data === "number" ? data : ""}
                checked={type === "checkbox" ? Boolean(data) : undefined}
            />
    );
}

I checked, if the input Field have the same key - but this wasnt the case. Also the key isnt constantly changing.

I checked in my browser and it seems like the form / page gets rerendered every time I make an input. That explains why my focus keeps getting lost, but i dont know how to fix this.


Solution

  • After some trial and error, I have found the error, but cannot explain exactly why it occurs.

    The error is actually caused by <FormLayout>. Because this is a component that is created with react-grid-layout. It works without this component.