Next.js
Kirim dari client component Next.js App Router, atau melalui server action dengan secret key.
Ada dua cara yang baik untuk mengirim dari Next.js. Kirim dari browser di client component, yang mempertahankan IP setiap pengunjung untuk rate limit dan berfungsi dengan semua pemeriksaan spam. Atau kirim dari server action, yang membuat formulir tetap berfungsi tanpa JavaScript.
| Item | Client component | Server action |
|---|---|---|
| Berfungsi tanpa JavaScript | Tidak | Ya |
| Rate limit dihitung per | Setiap pengunjung | IP server Anda |
| Pemeriksaan manusia Ikiform | Gunakan challenge dari SDK | Dilewati dengan secret key |
| Domain yang diizinkan | Dicocokkan dengan origin browser | Dilewati dengan secret key |
| Butuh secret key | Tidak | Ya |
Pasang SDK
npm install @ikiform/sdkSDK bersifat opsional. Semua yang di bawah juga berfungsi dengan fetch; lihat JavaScript dan fetch.
Dari client component
"use client";
import { submit } from "@ikiform/sdk";
import { useState } from "react";
type Status = "idle" | "sending" | "sent" | "error";
export function ContactForm() {
const [status, setStatus] = useState<Status>("idle");
const [errors, setErrors] = useState<Record<string, string[]>>({});
const [message, setMessage] = useState("");
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus("sending");
const result = await submit("frm_xxxxxxxxxxxxxxxx", new FormData(event.currentTarget));
if (result.ok) return setStatus("sent");
setErrors(result.error.fields ?? {});
setMessage(result.error.message);
setStatus("error");
}
if (status === "sent") return <p>Thanks, we got it.</p>;
return (
<form onSubmit={onSubmit} noValidate>
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required aria-invalid={Boolean(errors.email)} />
{errors.email ? <p>{errors.email[0]}</p> : null}
<label htmlFor="message">Message</label>
<textarea id="message" name="message" />
<input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
{status === "error" && !Object.keys(errors).length ? <p role="alert">{message}</p> : null}
<button disabled={status === "sending"}>{status === "sending" ? "Sending" : "Send"}</button>
</form>
);
}submittidak pernah melempar error. Hasilnya{ ok: true, id }atau{ ok: false, error, status, requestId }.error.fieldsmemetakan ID field ke pesan saat formulir punya field yang didefinisikan.- Render komponen dari halaman server component mana pun, misalnya
app/contact/page.tsx.
Dengan pemeriksaan manusia Ikiform
Jika pemeriksaan spam formulir adalah Ikiform, ambil token tepat sebelum setiap kiriman. challenge memasang frame kecil ikiform.com yang tetap tak terlihat kecuali Turnstile butuh klik.
const data = new FormData(event.currentTarget);
const turnstileToken = await challenge("frm_xxxxxxxxxxxxxxxx");
const result = await submit("frm_xxxxxxxxxxxxxxxx", data, { turnstileToken });Impor dengan import { challenge, submit } from "@ikiform/sdk";. Token hanya sekali pakai, jadi panggil sekali per kiriman.
Dari server action
Buat secret key di dashboard pada API keys dengan scope submissions:write, lalu simpan sebagai environment variable. Jangan pernah mengeksposnya ke browser: jangan beri awalan NEXT_PUBLIC_.
IKIFORM_SECRET_KEY=ik_sk_your_secret_key"use server";
export interface ContactState {
ok: boolean;
message: string;
fields?: Record<string, string[]>;
}
export async function sendContact(_previous: ContactState, formData: FormData): Promise<ContactState> {
const body = new URLSearchParams();
for (const [name, value] of formData) {
if (typeof value === "string" && !name.startsWith("$ACTION")) body.append(name, value);
}
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
method: "POST",
headers: {
Accept: "application/json",
Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
},
body,
});
const result = await response.json();
if (result.ok) return { ok: true, message: "Thanks, we got it." };
return { ok: false, message: result.error.message, fields: result.error.fields };
}"use client";
import { useActionState } from "react";
import { type ContactState, sendContact } from "./actions";
const initial: ContactState = { ok: false, message: "" };
export function ContactForm() {
const [state, action, pending] = useActionState(sendContact, initial);
if (state.ok) return <p>{state.message}</p>;
return (
<form action={action}>
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required />
{state.fields?.email ? <p>{state.fields.email[0]}</p> : null}
<label htmlFor="message">Message</label>
<textarea id="message" name="message" />
{state.message && !state.fields ? <p role="alert">{state.message}</p> : null}
<button disabled={pending}>{pending ? "Sending" : "Send"}</button>
</form>
);
}submit dari SDK juga bisa dipakai di server action, tetapi tidak mengirim header Authorization, jadi formulir dengan domain yang diizinkan atau pemeriksaan manusia Ikiform akan menolak atau menandai kirimannya. Gunakan fetch dengan secret key seperti contoh.
Terima webhook di route handler
Untuk memproses setiap kiriman di aplikasi Next.js Anda, tambahkan route handler. Lihat Menerima webhook.