safe-action-hooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesenext-safe-action React Hooks
next-safe-action React Hooks
Import
导入
ts
// Standard hooks
import { useAction, useOptimisticAction } from "next-safe-action/hooks";
// Deprecated — use React's useActionState directly instead
import { useStateAction } from "next-safe-action/stateful-hooks";ts
// Standard hooks
import { useAction, useOptimisticAction } from "next-safe-action/hooks";
// Deprecated — use React's useActionState directly instead
import { useStateAction } from "next-safe-action/stateful-hooks";useAction — Quick Start
useAction — 快速开始
tsx
"use client";
import { useAction } from "next-safe-action/hooks";
import { createUser } from "@/app/actions";
export function CreateUserForm() {
const { execute, result, status, isExecuting, isPending } = useAction(createUser, {
onSuccess: ({ data }) => {
console.log("User created:", data);
},
onError: ({ error }) => {
console.error("Failed:", error.serverError);
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
execute({ name: formData.get("name") as string });
}}>
<input name="name" required />
<button type="submit" disabled={isPending}>
{isPending ? "Creating..." : "Create User"}
</button>
{result.serverError && <p className="error">{result.serverError}</p>}
{result.data && <p className="success">Created: {result.data.id}</p>}
</form>
);
}tsx
"use client";
import { useAction } from "next-safe-action/hooks";
import { createUser } from "@/app/actions";
export function CreateUserForm() {
const { execute, result, status, isExecuting, isPending } = useAction(createUser, {
onSuccess: ({ data }) => {
console.log("User created:", data);
},
onError: ({ error }) => {
console.error("Failed:", error.serverError);
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
execute({ name: formData.get("name") as string });
}}>
<input name="name" required />
<button type="submit" disabled={isPending}>
{isPending ? "Creating..." : "Create User"}
</button>
{result.serverError && <p className="error">{result.serverError}</p>}
{result.data && <p className="success">Created: {result.data.id}</p>}
</form>
);
}useOptimisticAction — Quick Start
useOptimisticAction — 快速开始
tsx
"use client";
import { useOptimisticAction } from "next-safe-action/hooks";
import { toggleTodo } from "@/app/actions";
export function TodoItem({ todo }: { todo: Todo }) {
const { execute, optimisticState } = useOptimisticAction(toggleTodo, {
currentState: todo,
updateFn: (state, input) => ({
...state,
completed: !state.completed,
}),
});
return (
<label>
<input
type="checkbox"
checked={optimisticState.completed}
onChange={() => execute({ todoId: todo.id })}
/>
{todo.title}
</label>
);
}tsx
"use client";
import { useOptimisticAction } from "next-safe-action/hooks";
import { toggleTodo } from "@/app/actions";
export function TodoItem({ todo }: { todo: Todo }) {
const { execute, optimisticState } = useOptimisticAction(toggleTodo, {
currentState: todo,
updateFn: (state, input) => ({
...state,
completed: !state.completed,
}),
});
return (
<label>
<input
type="checkbox"
checked={optimisticState.completed}
onChange={() => execute({ todoId: todo.id })}
/>
{todo.title}
</label>
);
}Return Value
返回值
Both and return:
useActionuseOptimisticAction| Property | Type | Description |
|---|---|---|
| | Fire-and-forget execution |
| | Returns a promise with the result |
| | Last input passed to execute |
| | Last action result ( |
| | Resets all state to initial values |
| | Current status string |
| | No execution has started yet |
| | Action promise is pending |
| | React transition is pending |
| | |
| | Last execution returned data |
| | Last execution had an error |
| | Last execution triggered a navigation |
useOptimisticActionoptimisticStateStateuseActionuseOptimisticAction| 属性 | 类型 | 描述 |
|---|---|---|
| | 触发即忘式执行 |
| | 返回携带执行结果的Promise |
| | 最后一次传入execute的输入参数 |
| | 最后一次操作的结果 ( |
| | 将所有状态重置为初始值 |
| | 当前状态字符串 |
| | 尚未触发任何执行 |
| | 操作Promise处于pending状态 |
| | React过渡处于pending状态 |
| | 等价于 |
| | 最后一次执行返回了数据 |
| | 最后一次执行出现错误 |
| | 最后一次执行触发了页面跳转 |
useOptimisticActionoptimisticStateStateSupporting Docs
相关文档
- execute vs executeAsync, result handling
- Optimistic updates with useOptimisticAction
- Status lifecycle and all callbacks
- execute与executeAsync对比、结果处理
- 使用useOptimisticAction实现乐观更新
- 状态生命周期与全部回调
Anti-Patterns
反面模式
ts
// BAD: Using executeAsync without try/catch when navigation errors are possible
const handleClick = async () => {
const result = await executeAsync({ id }); // Throws on redirect!
showToast(result.data);
};
// GOOD: Wrap executeAsync in try/catch
const handleClick = async () => {
try {
const result = await executeAsync({ id });
showToast(result.data);
} catch (e) {
// Navigation errors (redirect, notFound) are re-thrown
// They'll be handled by Next.js — just let them propagate
throw e;
}
};ts
// BAD: Using executeAsync without try/catch when navigation errors are possible
const handleClick = async () => {
const result = await executeAsync({ id }); // Throws on redirect!
showToast(result.data);
};
// GOOD: Wrap executeAsync in try/catch
const handleClick = async () => {
try {
const result = await executeAsync({ id });
showToast(result.data);
} catch (e) {
// Navigation errors (redirect, notFound) are re-thrown
// They'll be handled by Next.js — just let them propagate
throw e;
}
};