How do you consume server actions response?
It might look as a silly question, but it is unclear for me how you must consume the response (either is it
If the action failed (form validation, db error, etc.), I'd like to retrieve this info in the response. In the network tab, the
result
or error
).
export default function Users() {
const users = useRouteData<typeof routeData>();
const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
await new Promise((resolve, reject) => setTimeout(resolve, 1000));
const email = String(formData.get("email"));
if (email.length < 10) {
return json({ success: false, fields: { email: "too small" } }); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}
await db.insert(usersTable).values({ email });
return json({ success: true });
}
);
createEffect(() => console.log("effect:", creating, creating.pending));
console.log(creating);
return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={creating.error}>Error: {creating.error/*???*/}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}
export default function Users() {
const users = useRouteData<typeof routeData>();
const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
await new Promise((resolve, reject) => setTimeout(resolve, 1000));
const email = String(formData.get("email"));
if (email.length < 10) {
return json({ success: false, fields: { email: "too small" } }); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}
await db.insert(usersTable).values({ email });
return json({ success: true });
}
);
createEffect(() => console.log("effect:", creating, creating.pending));
console.log(creating);
return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={creating.error}>Error: {creating.error/*???*/}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}
result
as the type Response
(it makes sense). However, how am I suppose to consume the response and extract the JSON I'm sending from the action?1 Reply
I could have an effect to extract the response data:
And maybe use a signal to set the response, but it seems very verbose. Is there a wrapper for automating that?
The "end" result would be:
Of course, things should be generic and stuff, but you get the gist. Am I missing a library that does the job?
Anyone? 🙂
createEffect(async () => {
if (creating.result) {
const res = await creating.result.json();
console.log({ res });
// do stuff with the response
}
});
createEffect(async () => {
if (creating.result) {
const res = await creating.result.json();
console.log({ res });
// do stuff with the response
}
});
export default function Users() {
const users = useRouteData<typeof routeData>();
const [error, setError] = createSignal<{ email?: string }>({});
const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
const email = String(formData.get("email"));
if (email.length < 10) {
return json(
{ success: false, fields: { email: "too small" } },
{ status: 400 }
); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}
await db.insert(usersTable).values({ email });
return json({ success: true });
}
);
createEffect(async () => {
if (creating.result && creating.result.status > 399) {
const res = (await creating.result.json()) as {
success: boolean;
fields: { email?: string };
};
setError(res.fields);
}
});
return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={error().email}>Error: {error().email}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}
export default function Users() {
const users = useRouteData<typeof routeData>();
const [error, setError] = createSignal<{ email?: string }>({});
const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
const email = String(formData.get("email"));
if (email.length < 10) {
return json(
{ success: false, fields: { email: "too small" } },
{ status: 400 }
); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}
await db.insert(usersTable).values({ email });
return json({ success: true });
}
);
createEffect(async () => {
if (creating.result && creating.result.status > 399) {
const res = (await creating.result.json()) as {
success: boolean;
fields: { email?: string };
};
setError(res.fields);
}
});
return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={error().email}>Error: {error().email}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}