Display loading or managing states for form is much easier now with the new useActionState
hook, whether you are using server actions or not. Let's see how to do it.
What is useActionState
?
useActionState
is a hook that allows you to update the state based on the form action. A Form action is a function triggered when a form is submitted. It could be a server action or a simple onSubmit
function.
This hook is only available in React's Canary version. You don't need to install anything, if you are using a new nextjs app. You can install the canary version by running the following command:
npm install react@canary react-dom@canary
We will create a simple login form that will trigger a server action to log in to the user.
I have an entire tutorial about the useActionState
hook where I have explained more deeply. I went over not only loading states but also how to handle input reset problems and how to update the state from the useActionState
hook.
How to use useActionState
with server actions?
A server action is a function that runs only on the server. So, you get access to all the server resources like database, file system, etc.
// src/actions.js
'use server'
// Simulate a server action
const wait = (ms = 3000) => new Promise(resolve => setTimeout(resolve, ms))
export const login = async (prevState, formData) => {
const email = formData.get('email')
const password = formData.get('password')
if (!email || !password) {
return {
error: 'Please fill in all fields',
message: null,
}
}
await wait()
return {
error: null,
message: 'Log in successful',
}
}
Explanation:
- Adding a
use server
directive to the file will make all functions a server action. -
login
action will take two arguments:prevState
andformData
.-
prevState
is the return value of the previous function call if the function was called more than once. Otherwise, it is going to be the initial state, passed as the second argument touseActionState
. -
formData
is the form data object that contains all the form field values.
-
- Get all the form field values using the
formData.get
method. - If the email or password is empty, return an error message.
- Wait for 3 seconds to simulate a server request.
- Assuming a successful response and Return a success message.
Now, let's create a login form and use the useActionState
hook to display loading states.
// src/LoginForm
'use client' // if using nextjs
const Page = () => {
const [state, formAction, isPending] = useActionState(login, {
message: null,
error: null,
})
const { message, error } = state
return (
<div className='flex justify-center items-center h-screen'>
<form action={formAction} className='w-96'>
<label className='form-control w-full'>
<div className='label'>
<span className='label-text'>Email</span>
</div>
<input
type='email'
placeholder='Email'
className='input input-bordered w-full '
name='email'
/>
</label>
<label className='form-control w-full'>
<div className='label'>
<span className='label-text'>Password</span>
</div>
<input
type='password'
placeholder='Password'
className='input input-bordered w-full '
name='password'
/>
</label>
<div className='label'>
<button disabled={isPending} className='btn btn-primary w-full'>
{isPending ? (
<span
className='loading loading-ring
loading-md'
></span>
) : (
Login
)}
</button>
</div>
{error && (
<div role='alert' className='alert alert-error'>
<span>Error! {error}</span>
</div>
)}
{message && (
<div role='alert' className='alert alert-success'>
<span>{message}</span>
</div>
)}
</form>
</div>
)
}
Explanation:
- The
useActionState
hook takes two arguments: the action function and the initial state object. - The hook returns three values:
state,
formAction
, andisPending.
-
state
is the return value of thelogin
action. -
formAction
is the function which you have passed to theuseActionState
hook. -
isPending
is a boolean value that is true when the form is submitted.
-
- Pass the
formAction
function to the form'saction
attribute. - Disable the button when the form is submitted and show a loading spinner.
- Show an error or success message based on the state.
That's it! You have successfully added loading states with server actions and the useActionState
hook in Nextjs 15 and React 19.
If it was helpful, please drop a 🩷 and subscribe to my YouTube channel for more tutorials.
Top comments (0)