Is useSubmission() not reactive?

Kind of puzzled here. So, TLDR, I am creating a contact form for a site I am developing. I need to update the UI when the form is submitted. So, naturally, I use useSubmission() as shown in the slimmed down snippet below (only showing the relevant parts as it’s kinda big). However, the UI doesn't update when the form is submitted. The form is being submitted, as I can confirm from my logs and the CRM its integrated with is getting the data). But, the UI isn't updating. Is useSubmission() not reactive? Or is there something I am doing wrong here?
const ContactPage: Component = () => {
const [messageSent, setMessageSent] = createSignal(false);
const submission = useSubmission(submitMessageAction);
const [serverError, setServerError] = createSignal("");

createEffect(() => {
logger.debug("Responding to Action");
const { error, result } = submission;
if (error) {
setServerError(error.message);
}

if (result) {
logger.debug("Form submitted successfully.");
if (result.statusCode === 200) {
setMessageSent(true);
}
}
});

return (
<MainLayout>
<Title>Contact - {siteName}</Title>
<main class="px-6 py-8 lg:px-8">
<PageHeader heading="Questions? Concerns? Or Just Want to Reach Out?" />
<section class=" mt-16 mx-auto max-w-2xl text-center">
<Show
when={!messageSent()}
fallback={
...
}
>
<Form action={submitMessageAction}>
<Show when={submission.error}>
<span>{(submission.error as Error).message}</span>
</Show>
<TextField
autocomplete="first_name"
id="first-name"
name="first-name"
placeholder="First Name"
edited={message.nameEdited.first}
onChange={(newValue) =>
updateFirstName(newValue.currentTarget.value)
}
validator={() => message.nameError.first}
/>
<TextField
autocomplete="last_name"
id="last-name"
name="last-name"
placeholder="Last Name"
edited={message.nameEdited.last}
onChange={(event) => updateLastName(event.currentTarget.value)}
validator={() => message.nameError.last}
/>
<TextField
autocomplete="email"
id="email"
name="email"
placeholder="Email Address"
type="email"
edited={message.emailEdited}
onChange={(event) => updateEmail(event.currentTarget.value)}
validator={() => message.emailError}
/>
<TextField
id="subject"
name="subject"
placeholder="Subject"
edited={message.subjectEdited}
onChange={(event) => updateSubject(event.currentTarget.value)}
validator={() => message.subjectError}
/>
<TextArea
name="message"
id="message"
rows={8}
placeholder="Your Message"
edited={message.messageEdited}
onChange={(event) => updateMessage(event.currentTarget.value)}
validator={() => message.messageError}
/>
<PrimaryActionButton
text={
submission.pending ? "Sending message..." : "Send Message"
}
type="submit"
disabled={!canSendMessage() && !submission.pending}
/>
</Form>
</Show>
</section>
</main>
</MainLayout>
);
const ContactPage: Component = () => {
const [messageSent, setMessageSent] = createSignal(false);
const submission = useSubmission(submitMessageAction);
const [serverError, setServerError] = createSignal("");

createEffect(() => {
logger.debug("Responding to Action");
const { error, result } = submission;
if (error) {
setServerError(error.message);
}

if (result) {
logger.debug("Form submitted successfully.");
if (result.statusCode === 200) {
setMessageSent(true);
}
}
});

return (
<MainLayout>
<Title>Contact - {siteName}</Title>
<main class="px-6 py-8 lg:px-8">
<PageHeader heading="Questions? Concerns? Or Just Want to Reach Out?" />
<section class=" mt-16 mx-auto max-w-2xl text-center">
<Show
when={!messageSent()}
fallback={
...
}
>
<Form action={submitMessageAction}>
<Show when={submission.error}>
<span>{(submission.error as Error).message}</span>
</Show>
<TextField
autocomplete="first_name"
id="first-name"
name="first-name"
placeholder="First Name"
edited={message.nameEdited.first}
onChange={(newValue) =>
updateFirstName(newValue.currentTarget.value)
}
validator={() => message.nameError.first}
/>
<TextField
autocomplete="last_name"
id="last-name"
name="last-name"
placeholder="Last Name"
edited={message.nameEdited.last}
onChange={(event) => updateLastName(event.currentTarget.value)}
validator={() => message.nameError.last}
/>
<TextField
autocomplete="email"
id="email"
name="email"
placeholder="Email Address"
type="email"
edited={message.emailEdited}
onChange={(event) => updateEmail(event.currentTarget.value)}
validator={() => message.emailError}
/>
<TextField
id="subject"
name="subject"
placeholder="Subject"
edited={message.subjectEdited}
onChange={(event) => updateSubject(event.currentTarget.value)}
validator={() => message.subjectError}
/>
<TextArea
name="message"
id="message"
rows={8}
placeholder="Your Message"
edited={message.messageEdited}
onChange={(event) => updateMessage(event.currentTarget.value)}
validator={() => message.messageError}
/>
<PrimaryActionButton
text={
submission.pending ? "Sending message..." : "Send Message"
}
type="submit"
disabled={!canSendMessage() && !submission.pending}
/>
</Form>
</Show>
</section>
</main>
</MainLayout>
);
2 Replies
Je Suis Un Ami
Je Suis Un AmiOP4mo ago
So, to clarify, when the form is submitted, I expect the effect to be executed, updating the form submission state. However, that’s not happening. And in my logs, the log messages in the effect are not displaying, which leads me to suspect useSubmission() isn’t triggering the reactivity system. Or at least how I have it here.
Madaxen86
Madaxen864mo ago
Here's a little example that shows that a. useSubmission is reactive and triggers effects b. how you can use the response helpers (json) to add something to the submission.result c. throw an error in the route. d. you don't need an additional signal for errors / messages From the code you posted I woudl assume that the action might not be an issue in the action or maybe the Form component. Does it have method="post"?
import { action, createAsync, json, query, useSubmission } from "@solidjs/router";
import { createEffect, Suspense } from "solid-js";
import Button from "~/components/Button";
let init = ["message"];
const getData = query(async () => {
"use server";
return init;
}, "getData");
const mutate = action(async (formData: FormData) => {
"use server";
const message = formData.get("message") as string;
if (message.length < 3) throw new Error("Message must be at least 3 characters");
init.push(message);
return json({ message: message + " - submitted successfull" }, { revalidate: getData.key });
}, "mutate");
const Form = () => {
const data = createAsync(() => getData());
const sub = useSubmission(mutate);
createEffect(() => console.log("isPending", sub.pending, "error", sub.error?.message, "result", sub.result));
return (
<div class="container mx-auto">
<div>
<p>
data:{" "}
<Suspense>
<pre>{JSON.stringify(data())}</pre>
</Suspense>
</p>
<p class="text-red-500">{sub.error?.message}</p>
<p>Result:{sub.result?.message}</p>
</div>
<form
action={mutate}
method="post"
class="grid gap-5"
>
<label html-for="message">Message</label>
<input
type="text"
name="message"
class="text-foreground p-4 border"
/>
<Button type="submit">Submit</Button>
</form>
</div>
);
};
export default Form;
import { action, createAsync, json, query, useSubmission } from "@solidjs/router";
import { createEffect, Suspense } from "solid-js";
import Button from "~/components/Button";
let init = ["message"];
const getData = query(async () => {
"use server";
return init;
}, "getData");
const mutate = action(async (formData: FormData) => {
"use server";
const message = formData.get("message") as string;
if (message.length < 3) throw new Error("Message must be at least 3 characters");
init.push(message);
return json({ message: message + " - submitted successfull" }, { revalidate: getData.key });
}, "mutate");
const Form = () => {
const data = createAsync(() => getData());
const sub = useSubmission(mutate);
createEffect(() => console.log("isPending", sub.pending, "error", sub.error?.message, "result", sub.result));
return (
<div class="container mx-auto">
<div>
<p>
data:{" "}
<Suspense>
<pre>{JSON.stringify(data())}</pre>
</Suspense>
</p>
<p class="text-red-500">{sub.error?.message}</p>
<p>Result:{sub.result?.message}</p>
</div>
<form
action={mutate}
method="post"
class="grid gap-5"
>
<label html-for="message">Message</label>
<input
type="text"
name="message"
class="text-foreground p-4 border"
/>
<Button type="submit">Submit</Button>
</form>
</div>
);
};
export default Form;

Did you find this page helpful?