skip to Main Content

So I am managing a form, that has 3 fields. Each of these 3 fields can have a default value. That default value however, needs to be fetched from the BE.

Now, I use useQuery in my app, so I just used that to fetch the 3 default values, that come in an object like this:
{ field1: string | null, field2: string | null, field3: string | null }

My code so far looks like something this (removed other non-relevant sections):

type TFormState = {
    field1: string | null;
    field2: string | null;
    field3: string | null;
};

const Detail = () => {
    
    const { currentId } = useParams();

    const [formState, setFormState] = useState<TFormState>({
        field1: null,
        field2: null,
        field3: null,
    });

    const defaultValues = useQuery({
        queryKey: ["getDefaultFormValues", currentId],
        queryFn: () => {
            if (!currentId) {
                return Promise.reject(new Error("No well id"));
            }
            return fetchDefaults();
        }
        enabled: !!currentId,
        refetchInterval: false,
    });

    return (
        <section>
            ...
            <form onSubmit={...}>
                <label htmlFor={"field1"}>Field 1 </label>
                <select id={"field1"} name={"field1"} value={formState.field1} onChange={...}>
                    {...}
                </select>
                <label htmlFor={"field2"}>Field 2 </label>
                <select id={"field2"} name={"field1"} value={formState.field1} onChange={...}>
                    {...}
                </select>
                <label htmlFor={"field3"}>Field 3 </label>
                <select id={"field3"} name={"field3"} value={formState.field1} onChange={...}>
                    {...}
                </select>
            </form>        
        </section>
    );
};

From now on, my ideas get kinda blurry.
What I’d do instinctually is to use a useEffect, and when defaultValues gets updated, I just set the state with the new default values. However, from what I’ve read online, using useEffect with useQuery is often an anti-pattern and should be avoided. (see https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose or https://github.com/TanStack/query/issues/3049)

However, I can’t just set the value of the various fields directly with the result of the query, since then the users wouldn’t be able to update the fields.

Is this one of the cases where useEffects are allowed? Or am I just looking at the problem from the wrong perspective and there is another way?

2

Answers


  1. Chosen as BEST ANSWER

    The comment of Adam Jenkins really helped me to better understand the problem.

    In the end, I extracted the form into another component with it's own props, and rendered it only when the default values have been fetched successfully.

    When the form is mounted, I get the default values from the props and use them to assign an initial value to the state.

    Thanks again!


  2. You’re right to be hesitant to use useEffect() – you don’t need it.

    Simply set each input’s value to local state if it exists, otherwise fallback to fetched values.

    <select id={"field1"} name={"field1"} value={formState.field1 ?? defaultValues.field1} onChange={...}>
                    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search