React Form Actions
Use useActionState to connect an asynchronous form action to pending feedback and a returned state.
How it works
React form actions can receive FormData and return a new action state. useActionState coordinates the state and pending flag for that flow. This course example uses a delayed local function, not a server function or a durable save. Disable the submit button while pending and report validation failures as state. Do not imply that the hook itself supplies authentication, a database or a secure API.
Run the code
Use a separate empty lab folder with Node 22.12+ in the 22 series. Save the files below using their displayed paths; browsers may download only the basename, so create src, public or tests folders as listed. The pinned project uses React and React DOM 19.3.1 with Vite 7.3.1. Run npm install, then npm run dev and open the local address Vite prints. React examples do not run in Bhylu’s current playground.
No Apache, MySQL or change to Bhylu’s server configuration is needed. These are local teaching projects, not a publishing package. Keep generated dependencies and lockfiles in your own lab. Review the project setup.
Example
import React, { StrictMode, useActionState } from 'react';
import { createRoot } from 'react-dom/client';
import './style.css';
async function preview(previous, data) {
await new Promise((resolve) => setTimeout(resolve, 80));
const item = String(data.get('item') || '').trim();
return item.length < 2
? 'Use at least two characters'
: 'Local action preview: ' + item + '. Not saved.';
}
function App() {
const [message, action, pending] = useActionState(preview, 'No action yet');
return (
<main>
<h1>Neighbourhood lending desk</h1>
<form action={action}>
<label>
Item
<input name="item" required defaultValue="Basket" />
</label>
<button disabled={pending}>
{pending ? 'Preparing…' : 'Prepare local preview'}
</button>
</form>
<output aria-live="polite">{message}</output>
</main>
);
}
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
);
Expected result
The action shows pending feedback and then a local-preview message. A one-character value returns a validation message.
The action receives previous state and submitted data; it returns the next message instead of mutating a shared variable. An uncontrolled field can reset after a successful action, so do not assume its text always remains. Real failures, retries and duplicate submissions need explicit design. The artificial delay exercises lifecycle behaviour without contacting an external service.
For API contracts and version differences, use React’s official documentation.