fabian-hiller / modular-forms

The modular and type-safe form library for SolidJS, Qwik and Preact
https://modularforms.dev
MIT License
995 stars 53 forks source link

[Qwik] Form state is reset after action returns an error #187

Open DustinJSilk opened 7 months ago

DustinJSilk commented 7 months ago

Hi fabian,

Sorry there's no way to reproduce this issue. I can't reproduce it outside of my production code yet. I'll try explain the problem and share some code that is similar but doesn't suffer from the same problem.. maybe you have an idea?

Latest qwik (1.4.5) and latest modular forms

Problem

If my formAction$ returns a server error the routeLoader$ refetches, the component rerenders, and all form state is reset. The error message that was returned then doesn't show and all values are reset. If I try again, it then works.

Interesting bits:

Example

This example doesn't have the same problem, but the code is quite similar but simplified.

import { Slot, component$, useComputed$, useSignal } from "@builder.io/qwik";
import { routeLoader$, z } from "@builder.io/qwik-city";
import { formAction$, useForm, zodForm$ } from "@modular-forms/qwik";

const schema = z.object({ value: z.number() });
type Form = z.infer<typeof schema>;

const useFormAction = formAction$<Form>(async () => {
  return {
    status: "error",
    message: "Some error message",
  };
}, zodForm$(schema));

export const useSomeData = routeLoader$(async () => {
  return {
    value: 100,
  };
});

export default component$(() => {
  const data = useSomeData();

  return (
    <div>
      <Toggle>
        <MyForm data={data.value}></MyForm>
      </Toggle>
    </div>
  );
});

const MyForm = component$((props: { data: { value: number } }) => {
  const initial = useComputed$(() => ({
    value: props.data.value * 2,
  }));

  const [form, { Form, Field }] = useForm<Form>({
    loader: initial,
    action: useFormAction(),
    validate: zodForm$(() => schema),
    validateOn: "submit",
  });

  return (
    <div>
      {initial.value.value}
      <Form>
        <Field name="value" type="number">
          {(field, p) => (
            <>
              <input {...p} type="number" value={field.value} />
              {field.error && <span>{field.error}</span>}
            </>
          )}
        </Field>

        {!form.submitting && form.response.status === "error" && (
          <p>{form.response.message ?? "Unknown error"}</p>
        )}

        <div>{!form.submitting && <button>Submit</button>}</div>
      </Form>
    </div>
  );
});

const Toggle = component$(() => {
  const show = useSignal(false);
  return (
    <div>
      <button onClick$={() => (show.value = !show.value)}>Toggle</button>

      {show.value && <Slot />}
    </div>
  );
});

Thanks for all the amazing work on this! I'll try reproduce the problem eventually.

fabian-hiller commented 7 months ago

For the transform problem this might help. For the other problem, I don't know what to do. Seems more like a Qwik problem than a Modular Forms problem.