Open palmjack opened 4 days ago
Not sure if I'm missing something, but how can it work with JS disabled if you're using the action via a hook, which is a JavaScript function by definition? Don't think this is related to next-safe-action. I guess progressive enhancement is only available if you're passing the Server Action directly to the form action.
First, I tested the executeFormAction
exported by zsa's useServerAction
, which also does not support progressive enhancement. If I write it like this, I will still get an unsupported error prompt, just like this:
export function UseZsaStateExaple() {
const { isPending, executeFormAction, data, error } =
useServerAction(produceNewMessage);
return (
<div>
<form action={executeFormAction}>
<input name="name" placeholder="Enter your name..." />
<button type="submit" disabled={isPending}>
submit me
</button>
</form>
{isPending && <div>Loading...</div>}
{data && <p>Message: {data}</p>}
{error && <div>Error: {JSON.stringify(error)}</div>}
</div>
);
}
In addition, if you want to support progressive enhancement, you need to use the official useActionState
of React, and the example of zsa is the same
"use client";
import { useActionState } from "react";
import { produceNewMessage } from "./actions";
export default function UseActionStateExample() {
let [[data, err], submitAction, isPending] = useActionState(
produceNewMessage,
[null, null] // or [initialData, null]
);
return (
<div>
<form action={submitAction}>
<input name="name" placeholder="Enter your name..." />
<button type="submit" disabled={isPending}>
submit me
</button>
</form>
{isPending && <div>Loading...</div>}
{data && <p>Message: {data}</p>}
{error && <div>Error: {JSON.stringify(error)}</div>}
</div>
);
}
Here is an example of using useActionState
to support progressive enhancement in next-safe-action
// actions.ts
'use server'
import { createSafeActionClient } from "next-safe-action"
import { zfd } from "zod-form-data";
export const produceNewMessageAction = createSafeActionClient()
.schema(
zfd.formData({
name: zfd.text(),
})
)
.stateAction(async ({ parsedInput }) => {
await new Promise((resolve) => { setTimeout(resolve, 500) })
return "Hello, " + parsedInput.name
})
"use client"
import { useActionState } from "react";
import { produceNewMessageAction } from "./actions";
export function UseActionStateExample() {
const [state, submitAction, isPending] = useActionState(
produceNewMessageAction,
{}
);
return (
<div>
<form action={submitAction}>
<input name="name" placeholder="Enter your name..." />
<button type="submit" disabled={isPending}>submit me</button>
</form>
{isPending && <div>Loading...</div>}
{state.data && <p>Message: {state.data}</p>}
{state.validationErrors && <div>Error: {JSON.stringify(state.validationErrors)}</div>}
</div>
);
}
Thanks for making it clear. I think it could be a good idea to clearly state it in the docs that if you want progressive enhancement you need to use react native hook.
As @tenghuan123 said, progressive enhancement is available via useActionState
hook from React.
next-safe-action exports a hook called useStateAction
from /stateful-hooks
path, but I've just tested it and it doesn't work with JavaScript disabled. The execute
function returned from that hook is a wrapper of the dispatcher from React's useActionState
hook. This is because otherwise useful props (such as status and client input) couldn't be returned from the hook — see the image below. *
Now I'm actually thinking of changing the useStateAction
API to just return the [state, action, isPending]
original array or remove the stateful hook entirely from the library and tell users to use the React one.
If this will be the case, the useStateAction
hook will be marked as deprecated for a number of minor versions and then removed.
What do you think?
* useStateAction
return object:
Are you using the latest version of this library?
Is there an existing issue for this?
Describe the bug
Sending form with js disabled does not work when using
useAction
hook.Reproduction steps
See attached screenshot of the form element![CleanShot 2024-07-02 at 12 48 01@2x](https://github.com/TheEdoRan/next-safe-action/assets/3027293/0c6e3cdd-2808-4bf3-abbf-24cbd032de5f)
Expected behavior
Form should be sent with javascript disabled, at least that's what I understand from looking at the example in the docs https://next-safe-action.dev/docs/recipes/form-actions
Minimal reproduction example
https://next-safe-action-playground.vercel.app/stateless-form
Operating System
macOS
Library version
7.1.3
Next.js version
15.0.0-rc.0
Additional context
No response