Skip to content

Instantly share code, notes, and snippets.

@tung1404
Forked from mishushakov/client.tsx
Created June 5, 2024 04:40
Show Gist options
  • Save tung1404/91d069a6e63bdf9ad52c8dfd5c6eef6f to your computer and use it in GitHub Desktop.
Save tung1404/91d069a6e63bdf9ad52c8dfd5c6eef6f to your computer and use it in GitHub Desktop.
A React hook for calling Next.js Server Actions from client components
'use client'
import { test } from './server'
import { useServerAction } from './hook'
export default function Home() {
const { data, loading, error, execute: testAction } = useServerAction(test)
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<>
<form action={testAction}>
<input type="text" name='name' />
<button type="submit">Submit</button>
</form>
<div>{data}</div>
</>
)
}
'use server'
export async function test(form: FormData) {
const name = form.get('name')
return name?.toString()
}
import { useState } from 'react'
type AsyncFunction = (...args: any) => Promise<any>
export function useServerAction<T extends AsyncFunction>(action: T) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState<Error | null | undefined>(null)
const [data, setData] = useState<Awaited<ReturnType<T>> | null | undefined>(null)
async function execute (...payload: Parameters<T>) {
setLoading(true)
setError(null)
setData(null)
try {
const res = await action(payload)
setData(res)
} catch (e: any) {
setError(e)
}
setLoading(false)
}
return {
data,
loading,
error,
execute
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment