NodeJS 在React App中为联系人表单使用SendGrid模块时出错

y53ybaqx  于 2023-06-29  发布在  Node.js
关注(0)|答案(1)|浏览(139)

我正在尝试在我的React网站中使用SendGrid模块实现联系表单以发送电子邮件。我在一个名为server.js的文件中有服务器端代码,在card. tsx中有客户端代码。当我运行npm start时,我遇到了一个与SendGrid包中的fs和path模块相关的错误。另外,我在Contact.tsx文件中的类型检查有问题。如何解决这些错误并使联系表格正常工作?
下面是我在server.js中的服务器端代码:

// server.js
const express = require("express");
const sgMail = require("@sendgrid/mail");
const { resolve } = require("path-browserify");

// Set up SendGrid API key
sgMail.setApiKey("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");

// Create Express app
const app = express();

// Middleware to parse JSON requests
app.use(express.json());

app.get("/", (req, res) => {
  res.send("Hello, server!");
});

// Route to handle sending emails
app.post("/send-email", (req, res) => {
  const { Name, Email, Message, submitbutton } = req.body;

  const msg = {
    to: "paristiffany12@gmail.com",
    from: "gdscusyd@gmail.com",
    subject: "Example Subject",
    text: `Name: ${Name}\nEmail: ${Email}\nMessage: ${Message}\nSubmit Button: ${submitbutton}`,
    html: `<p>Name: ${Name}</p><p>Email: ${Email}</p><p>Message: ${Message}</p><p>Submit Button: ${submitbutton}</p>`,
  };

  sgMail
    .send(msg)
    .then(() => {
      res.status(200).json({ message: "Email sent successfully" });
    })
    .catch((error) => {
      console.error(error.toString());
      res.status(500).json({ error: "Failed to send email" });
    });
});

// Set up fallback for path module
resolve.fallback = { path: require.resolve("path-browserify") };

// Start the server
app.listen(4000, () => {
  console.log("Server started on port 3000");
});

下面是card.tsx中的客户端代码(联系表单的代码):

import React, { useState, useEffect, useRef } from "react";
import cardcss from "./Card.module.css";
import axios from "axios";

interface CardProps {
  imageUrl: string;
  title: string;
  body: string;
}

function Card(props: CardProps) {
  const [message, setMessage] = useState("");
  const nameInputRef = useRef<HTMLInputElement>(null);
  const emailInputRef = useRef<HTMLInputElement>(null);
  const messageInputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (messageInputRef.current) {
      messageInputRef.current.focus();
      messageInputRef.current.setSelectionRange(0, 0);

      // Delay setting the cursor position
      setTimeout(() => {
        messageInputRef.current?.setSelectionRange(0, 0);
      }, 0);
    }
  }, []);

  const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
    event.target.setSelectionRange(0, 0);
  };

  const submitHandler = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    if (
      nameInputRef.current &&
      emailInputRef.current &&
      messageInputRef.current
    ) {
      const nameInput = nameInputRef.current.value;
      const emailInput = emailInputRef.current.value;
      const messageInput = messageInputRef.current.value;

      const contactData = {
        Name: nameInput,
        Email: emailInput,
        Message: messageInput,
      };

      axios
        .post("/send-email", contactData)
        .then((response) => {
          console.log(response.data);
          // Handle success response
        })
        .catch((error) => {
          console.error(error);
          // Handle error response
        });
    }
  };

  return (
    <div className={cardcss.cardcontainer}>
      <div className={cardcss.imagecontainer}>
        <img src={props.imageUrl} alt="" />
      </div>

      <div className={cardcss.cardtitle}>
        <h3>{props.title}</h3>
      </div>

      <div className={cardcss.cardbody}>
        <p>{props.body}</p>

        <form onSubmit={submitHandler}>
          <div>
            <label className={cardcss.namelabel} htmlFor="name">
              Name:
            </label>
            <input
              className={cardcss.nameinput}
              type="text"
              id="name"
              name="name"
              ref={nameInputRef}
            />
          </div>

          <div className={cardcss.emailcontainer}>
            <label className={cardcss.emaillabel} htmlFor="email">
              Email:
            </label>
            <input
              className={cardcss.emailinput}
              type="text"
              id="email"
              name="email"
              ref={emailInputRef}
            />
          </div>

          <div className={cardcss.messagecontainer}>
            <label className={cardcss.messagelabel} htmlFor="message">
              Message:
            </label>
            <input
              ref={messageInputRef}
              className={cardcss.messageinput}
              type="text"
              id="message"
              name="message"
              value={message}
              onChange={(e) => setMessage(e.target.value)}
              onFocus={handleFocus}
            />

            <button className={cardcss.sendbutton} type="submit">
              Send
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

export default Card;

下面是我的联系人页面代码:

import React, { useRef } from "react";
import contactcss from "./Contact.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Card from "../../components/ui/Card";
import {
  faInstagram,
  faFacebook,
  faLinkedin,
  faDiscord,
} from "@fortawesome/free-brands-svg-icons";
import emaillogo from "../../resources/email-logo.png";
import { setApiKey, send } from "@sendgrid/mail";

const Contact: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = () => {
    if (inputRef.current) {
      inputRef.current.focus();
      inputRef.current.setSelectionRange(0, 0);
    }
  };

  setApiKey(
    "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"
  ); 

  function submitFormHandler(contactData: {
    Name: string;
    Email: string;
    Message: string;
  }) {
    const { Name, Email, Message } = contactData;

    const msg = {
      to: "paristiffany12@gmail.com",
      from: Email,
      subject: "GDSC Contact Form - New Message",
      text: `Message from: ${Name}\nMessage: ${Message}`,
      html: `<p>Message from: ${Name}</p><p>Message: ${Message}</p>`,
    };

    send(msg)
      .then(() => {
        console.log("Email sent successfully");
      })
      .catch((error) => {
        console.error(error.toString());
      });
  }

  return (
    <div>
      <div>
        <div className={contactcss.background}>
          <img
            className={contactcss.emaillogo}
            src={emaillogo}
            alt="Contact Us"
          />
          <div className={contactcss.contact}>Contact Us</div>
        </div>
      </div>

      <Card
        title="We're keen to hear from you!"
        imageUrl="https://images.app.goo.gl/D6m6hHMnP1gjsKKV7"
        body=""
        onSubmitForm={submitFormHandler}
      />

      <div className={contactcss.whitebackground}>
        <div className={contactcss.socials}>
          <h1>Follow Our Socials</h1>
          <p className={contactcss.socialmedia}>
            Stay connected with GDSC USYD by following us on our social media
            channels:
          </p>
          <div>
            <a href="https://www.instagram.com/gdscusyd/">
              <FontAwesomeIcon
                className={contactcss.instagram}
                icon={faInstagram}
              />
            </a>

            <a href="https://www.facebook.com/gdsc.usyd">
              <FontAwesomeIcon
                className={contactcss.facebook}
                icon={faFacebook}
              />
            </a>

            <a href="https://discord.com/channels/872033047652990986/872033047652990989">
              <FontAwesomeIcon
                className={contactcss.discord}
                icon={faDiscord}
              />
            </a>

            <a href="https://www.linkedin.com/company/gdsc-usyd/">
              <FontAwesomeIcon
                className={contactcss.linkedin}
                icon={faLinkedin}
              />
            </a>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Contact;

错误消息:
编译失败。未找到模块:错误:无法解析'fs' in '/Users/parisvinuya/RARYA - GDSC WEBSITE/gdsc-website/main/node_modules/@sendgrid/helpers/classes'
我想知道我如何才能让这个联系表格工作?我已经把服务器端代码和客户端代码分开了,但是网站仍然没有运行……谢谢你的帮助!

kyxcudwk

kyxcudwk1#

首先,你不应该在客户端实现SendGrid API(React)。您的联系人表单应该包含将表单数据发送到后端的逻辑,并让后端实现发送电子邮件的逻辑。
这样,您就可以在应用程序的客户端和服务器端使用相同的包。正如我在前一段中所说的,你不应该在客户端实现电子邮件逻辑。在客户端保存和发送API密钥既不安全也不负责,因为它很容易被盗。
在编译客户端代码时遇到fs错误的原因是客户端(浏览器运行JavaScript)不包含fs模块。fs模块代表文件系统,仅在操作系统上运行的NodeJS中实现。
要修复此问题,请从客户端删除与SendGrid相关的所有逻辑,并让服务器端API接收表单输入并将所需消息发送给用户。
换句话说,接触组件:

import React, { useRef } from "react";
import contactcss from "./Contact.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Card from "../../components/ui/Card";
import {
  faInstagram,
  faFacebook,
  faLinkedin,
  faDiscord,
} from "@fortawesome/free-brands-svg-icons";
import emaillogo from "../../resources/email-logo.png";
// import { setApiKey, send } from "@sendgrid/mail"; // This should be removed

const Contact: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = () => {
    if (inputRef.current) {
      inputRef.current.focus();
      inputRef.current.setSelectionRange(0, 0);
    }
  };

  const handleSendMessageToApi => async (data: any) => {
    const response = await fetch(YOUR_API_URI, {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        'Content-type': 'application/json',
      },
    });
    return await response.json();
  }
/* This should be removed
  setApiKey(
    "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"
  ); 
*/ 
  function submitFormHandler(contactData: {
    Name: string;
    Email: string;
    Message: string;
  }) {
    const { Name, Email, Message } = contactData;
    
    /* This should be removed
    const msg = {
      to: "paristiffany12@gmail.com",
      from: Email,
      subject: "GDSC Contact Form - New Message",
      text: `Message from: ${Name}\nMessage: ${Message}`,
      html: `<p>Message from: ${Name}</p><p>Message: ${Message}</p>`,
    }; 

    send(msg)
      .then(() => {
        console.log("Email sent successfully");
      })
      .catch((error) => {
        console.error(error.toString());
      }); */
      
      // Replace code above with your own implementation as below.
      // Your implementation might differ, make changes based on your use case.
      handleSendMessageToApi(contactData)
        .then((apiResponse) => console.log(apiResponse))
        .catch(err => console.error(err));
  }

  return (
    <div>
      <div>
        <div className={contactcss.background}>
          <img
            className={contactcss.emaillogo}
            src={emaillogo}
            alt="Contact Us"
          />
          <div className={contactcss.contact}>Contact Us</div>
        </div>
      </div>

      <Card
        title="We're keen to hear from you!"
        imageUrl="https://images.app.goo.gl/D6m6hHMnP1gjsKKV7"
        body=""
        onSubmitForm={submitFormHandler}
      />

      <div className={contactcss.whitebackground}>
        <div className={contactcss.socials}>
          <h1>Follow Our Socials</h1>
          <p className={contactcss.socialmedia}>
            Stay connected with GDSC USYD by following us on our social media
            channels:
          </p>
          <div>
            <a href="https://www.instagram.com/gdscusyd/">
              <FontAwesomeIcon
                className={contactcss.instagram}
                icon={faInstagram}
              />
            </a>

            <a href="https://www.facebook.com/gdsc.usyd">
              <FontAwesomeIcon
                className={contactcss.facebook}
                icon={faFacebook}
              />
            </a>

            <a href="https://discord.com/channels/872033047652990986/872033047652990989">
              <FontAwesomeIcon
                className={contactcss.discord}
                icon={faDiscord}
              />
            </a>

            <a href="https://www.linkedin.com/company/gdsc-usyd/">
              <FontAwesomeIcon
                className={contactcss.linkedin}
                icon={faLinkedin}
              />
            </a>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Contact;

有了上面的更改,您应该重构服务器端代码,以接收数据并使用API向用户发送电子邮件。我还没看过后端代码所以要做出相应的改变
希望这个答案有用。

相关问题