如何使用服务器操作 POST 向端点 nextjs 发送数据

问题描述 投票:0回答:1

我在父组件中有不同的步骤,其中之一我使用静态方法 Array.from()。现在我正在学习服务器操作并希望使用 POST 将数据发送到端点。

if (prev.step === 2) {
const singleGuests = Array.from(
  { length: prev.tickets.single },

 formData.
  (_, i) => ({
    firstName: formData.get(`single_firstName_${i}`),
    lastName: formData.get(`single_lastName_${i}`),
    email: formData.get(`single_email_${i}`),
    phonenumber: formData.get(`single_phonenumber_${i}`),
  })
);
const vipGuests = Array.from({ length: prev.tickets.vip }, (_, i) => ({
  firstName: formData.get(`vip_firstName_${i}`),
  lastName: formData.get(`vip_lastName_${i}`),
  email: formData.get(`vip_email_${i}`),
  phonenumber: formData.get(`vip_phonenumber_${i}`),
}));
return {
  ...prev,
  step: prev.step + 1,
  guests: { single: singleGuests, vip: vipGuests },
};

}

import { useState } from "react";
import { motion } from "framer-motion";
import { Caesar_Dressing } from "next/font/google";

const ceasarDressing = Caesar_Dressing({
  subsets: ["latin"],
  weight: "400",
  display: "swap",
});

export default function ContactInfo({ tickets, formAction }) {
  const [isFormValid, setIsFormValid] = useState(false);

  const handleInputChange = (e) => {
    const inputs = e.target.closest("form").querySelectorAll("input");
    const allValid = Array.from(inputs).every((input) => input.checkValidity());
    setIsFormValid(allValid);
  };

  return (
    <motion.form
      initial={{ opacity: 0, x: 20 }}
      animate={{ opacity: 1, x: 0 }}
      transition={{ duration: 0.3 }}
      className="text-white rounded-lg bg-gradient-to-tl border border-gray-500 from-customBlack_2 to-customBlack p-4 relative z-0"
      onChange={handleInputChange}
    >
      <fieldset className="grid gap-6 mb-6 md:grid-cols-2">
        <legend className={`${ceasarDressing.className} block mb-2 text-3xl`}>
          PERSONLIG INFORMATION
        </legend>
        {Array.from({ length: tickets.single }, (_, i) => (
          <ContactForm key={i} i={i} ticketType="single" />
        ))}
        <div className="relative z-10 group rounded-xl inline-block p-[2px] overflow-hidden shadow-lg">
          <span className="absolute inset-[-1000%] animate-[spin_3s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#EC2783_0%,#141415_50%,#EC2783_100%)]" />
          <div className="relative bg-gradient-to-tl from-customBlack_2 to-customBlack z-0 rounded-xl">
            <div className="rounded-xl overflow-hidden">
              {Array.from({ length: tickets.vip }, (_, i) => (
                <ContactForm key={i} i={i} ticketType="vip" />
              ))}
            </div>
          </div>
        </div>
      </fieldset>
      <div className="flex">
        <button
          className={`${
            isFormValid
              ? "font-bold px-8 py-2 my-8 ml-auto text-xl bg-gradient-to-bl from-customPink text-white to-customOrange text-transparent hover:transform"
              : "bg-gray-500 px-8 py-2 my-8 ml-auto text-xl font-bold text-gray-300 cursor-not-allowed"
          }`}
          formAction={formAction}
          type="submit"
          disabled={!isFormValid}
        >
          Næste
        </button>
      </div>
    </motion.form>
  );
}

function ContactForm({ i, ticketType }) {
  //Her bruger jeg staggerChildren så jeg giver hver children en lille delay-animation
  // Tilføjer i parent komponenten en variant/tilstand på children komponenterne kan arve det vider.
  // Derefter giver jeg hver children inputSpring, hvordan de skal animeres ind (har gjort det som konstant)
  const staggerInputs = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: 0.2,
      },
    },
  };

  const inputSpring = {
    hidden: { opacity: 0, y: 20 },
    visible: {
      opacity: 1,
      y: 0,
      transition: { type: "spring", stiffness: 100 },
    },
  };

  return (
    <motion.div
      initial="hidden"
      animate="visible"
      variants={staggerInputs}
      className="p-2"
    >
    {/* ticketType kigger om det en single/vip og laver en conditionel rendering. Vi gav den property tidligere til Cards i ChooseTickets-komponenten. */}
      {ticketType === "single" && (
        <motion.h2 className="font-bold text-xl" variants={inputSpring}>
          Enkelt Billet
        </motion.h2>
      )}
      {ticketType === "vip" && (
        <motion.h2
          variants={inputSpring}
          className="font-bold text-xl bg-gradient-to-r from-customPink via-customRed to-customOrange bg-clip-text text-transparent"
        >
          VIP Billet
        </motion.h2>
      )}

      <motion.div className="mb-2.5" variants={inputSpring}>
        <label
          htmlFor={`${ticketType}_firstName_${i}`}
          className="block text-sm font-medium text-white"
        >
          Fornavn
        </label>
        <input
          name={`${ticketType}_firstName_${i}`}
          type="text"
          placeholder="Joe"
          autoComplete="name"
          required
          className="bg-gray-100 border border-gray-200 text-gray-900 text-sm rounded-md w-full p-2.5 focus:outline-none focus:ring-2 valid:[&:not(:placeholder-shown):not(:focus)]:bg-green-50 valid:[&:not(:placeholder-shown):not(:focus)]:border-green-500 valid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-green-500 invalid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-red-500 invalid:[&:not(:placeholder-shown):not(:focus)]:bg-red-50 invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400"
        />
      </motion.div>

      <motion.div className="mb-2.5" variants={inputSpring}>
        <label
          htmlFor={`${ticketType}_lastName_${i}`}
          className="block text-sm font-medium text-white"
        >
          Efternavn
        </label>
        <input
          name={`${ticketType}_lastName_${i}`}
          type="text"
          placeholder="Doe"
          autoComplete="name"
          required
          className="bg-gray-100 border border-gray-200 text-gray-900 text-sm rounded-md w-full p-2.5 focus:outline-none focus:ring-2 valid:[&:not(:placeholder-shown):not(:focus)]:bg-green-50 valid:[&:not(:placeholder-shown):not(:focus)]:border-green-500 valid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-green-500 invalid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-red-500 invalid:[&:not(:placeholder-shown):not(:focus)]:bg-red-50 invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400"
        />
      </motion.div>

      <motion.div className="mb-2.5" variants={inputSpring}>
        <label htmlFor={`${ticketType}_email_${i}`}>Email</label>
        <input
          className="bg-gray-100 border border-gray-200 text-gray-900 text-sm rounded-md w-full p-2.5 focus:outline-none focus:ring-2 valid:[&:not(:placeholder-shown):not(:focus)]:bg-green-50 valid:[&:not(:placeholder-shown):not(:focus)]:border-green-500 valid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-green-500 invalid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-red-500 invalid:[&:not(:placeholder-shown):not(:focus)]:bg-red-50 invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400"
          name={`${ticketType}_email_${i}`}
          type="email"
          placeholder="[email protected]"
          autoComplete="email"
          required
        />
      </motion.div>

      <motion.div className="mb-2.5" variants={inputSpring}>
        <label htmlFor={`${ticketType}_phonenumber_${i}`}>Mobilnummer</label>
        <input
          name={`${ticketType}_phonenumber_${i}`}
          type="tel"
          placeholder="12 34 56 78"
          autoComplete="tel"
          required
          className="bg-gray-100 border border-gray-200 text-gray-900 text-sm rounded-md w-full p-2.5 focus:outline-none focus:ring-2 valid:[&:not(:placeholder-shown):not(:focus)]:bg-green-50 valid:[&:not(:placeholder-shown):not(:focus)]:border-green-500 valid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-green-500 invalid:[&:not(:placeholder-shown):not(:focus)]:focus:ring-red-500 invalid:[&:not(:placeholder-shown):not(:focus)]:bg-red-50 invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400"
        />
      </motion.div>
    </motion.div>
  );
}

到目前为止,我已将函数发送到我的子组件并再次使用数组方法,但从现在起我不知道如何将数据发送到终点:

reactjs next.js react-hooks http-post server-action
1个回答
0
投票

在 Next.js 中,您可以使用服务器操作(在 Next.js 13+ 中通过 App Router 引入)将 POST 请求发送到端点。服务器操作允许您直接执行服务器端操作,例如表单提交或数据更新。

export async function sendDataToServer(formData) {
  "use server";
  const endpoint = "https://api.example.com/data"; // Replace with your endpoint
  await fetch(endpoint, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      name: formData.get("name"),
      email: formData.get("email"),
    }),
  });
}

export default function Page() {
  return (
    <form action={sendDataToServer} className="p-6">
      <input name="name" placeholder="Name" className="border p-2 m-2" />
      <input name="email" placeholder="Email" className="border p-2 m-2" />
      <button type="submit" className="bg-blue-500 text-white p-2">Submit</button>
    </form>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.