Hey everyone,
I’m currently diving into backend development using Next.js and have hit a snag that I’m hoping someone can help me with. I’ve spent the last 5 months getting to grips with HTML, CSS, and JavaScript, and I’m now venturing into the exciting (and sometimes confusing!) world of backend.
I’m following a YouTube tutorialthat was posted about two months ago, which seems to be using a similar stack to what I’m aiming for: Next.js 15, React 19, shadcn/ui for components, PostgreSQL for the database, Zustand for state management, Prisma as my ORM, and Lucia Auth for handling authentication.
The problem I’m encountering is during the account creation process. When I try to submit the signup form, I get the following error in my console:
TypeError: action is not a function
I’ve been trying to debug this for a while now, but as I’m still very new to backend concepts, I’m feeling a bit lost. From what I understand, this error usually means I’m trying to call something that isn’t actually a function. I suspect it might have something to do with how I’ve set up my form submission and the associated server-side logic (which I believe Next.js handles with Server Actions?).
Here’s a snippet of the relevant code from my SignUp
component (it’s a Client Component using 'use client'
):
JavaScript
'use client';
import React, { useActionState } from 'react';
import Form from 'next/form';
import { Loader2 } from 'lucide-react';
const initialState = {
message: '',
};
type SignUpProps = {
action: (prevState: any, formData: FormData) => Promise<{ message: string } | undefined>;
};
const SignUp = ({ action }: SignUpProps) => {
const [state, formAction, isPending] = useActionState(action, initialState);
return (
// ... (rest of my JSX for the signup form)
<Form action={formAction} className="...">
{/* ... form fields ... */}
<button type="submit" disabled={isPending}>
{isPending ? <><Loader2 className="h-4 w-4 animate-spin" /> Creating Account...</> : 'Create Account'}
</button>
</Form>
// ... (rest of my JSX)
);
};
export default SignUp;
And here’s how I’m calling this component in my page.tsx
file (I think this is where the “action” prop is being passed):
JavaScript
'use server';
import { getCurrentSession, registerUser, loginUser } from '@/actions/auth'; // Assuming my auth actions are here
import SignUp from '@/components/layout/auth/SignUp';
import { redirect } from 'next/navigation';
import React from 'react';
import zod from 'zod';
const SignUpSchema = zod.object({
email: zod.string().email(),
password: zod.string().min(5),
});
const SignUpPage = async () => {
const { user } = await getCurrentSession();
if (user) {
return redirect('/');
}
const action = async (prevState: any, formData: FormData) => {
const parsed = SignUpSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) {
return { message: "Invalid form data" };
}
const { email, password } = parsed.data;
const { user, error } = await registerUser(email, password);
if (error) {
return { message: error };
} else if (user) {
await loginUser(email, password);
return redirect("/");
}
};
return <SignUp action={action} />;
};
export default SignUpPage;
My registerUser
and loginUser
functions are in a separate auth.ts
file within my actions
directory, and they both have "use server"
at the top.
I’m really trying to understand how Server Actions and useActionState
work together, but this error is throwing me off. Any guidance or pointers on what I might be doing wrong would be hugely appreciated!
Thanks in advance for your help.