"use client";
import classes from "./ContactEmailForm.module.css";
import SuccessOrFail from "./SuccessOrFail";
import { useRef, useState, useEffect } from "react";
type Email = {
email: string;
subject: string;
message: string;
};
export default function ContactEmailForm() {
const emailRef = useRef<HTMLInputElement>(null);
const subjectRef = useRef<HTMLInputElement>(null);
const messageRef = useRef<HTMLTextAreaElement>(null);
const [submitComplete, setSubmitComplete] = useState(false);
const submitHandler = async (e: React.MouseEvent<HTMLFormElement>) => {
e.preventDefault();
if (emailRef.current && subjectRef.current && messageRef.current) {
const email = emailRef.current.value;
const subject = subjectRef.current.value;
const message = messageRef.current.value;
await sendEmail({
email,
subject,
message,
});
emailRef.current.value = "";
subjectRef.current.value = "";
messageRef.current.value = "";
setSubmitComplete(true);
}
};
const sendEmail = async ({ email, subject, message }: Email) => {
try {
const res = await fetch("http://localhost:3002/api/contact", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
subject,
message,
}),
});
if (!res.ok) {
throw new Error("서버 요청에 실패하였습니다!");
}
const data = await res.json();
console.log(data);
} catch (err) {}
};
useEffect(() => {
const showSumbitComplte = setTimeout(() => {
setSubmitComplete(false);
}, 3000);
return () => {
clearTimeout(showSumbitComplte);
};
}, [submitComplete]);
return (
<>
<div className={classes.email_form_container}>
{submitComplete && <SuccessOrFail />}
<form className={classes.contact_form} onSubmit={submitHandler}>
<div className={classes.email_input}>
<label htmlFor="email">Your Email</label>
<input ref={emailRef} type={"email"} name="email" id="email" />
</div>
<div className={classes.subject_input}>
<label htmlFor="subject">Subject</label>
<input ref={subjectRef} type={"text"} name="subject" id="subject" />
</div>
<div className={classes.message_input}>
<label htmlFor="message">Message</label>
<div>
<textarea ref={messageRef} name="message" id="message" />
</div>
</div>
<div className={classes.button_container}>
<button className={classes.button}>Submit</button>
</div>
</form>
</div>
</>
);
}
useState는 요청이 들어올때마다 리렌더링이 일어나는게 아니라, 효율성을 위해 여러번의 요청을 한번에 업데이트하는 batch update가 일어난다. 또한 비동기적으로 일어난다.
form 내용 같은 경우는 굳이 계속 업데이트 해줄 필요 없이 마지막에 post 요청이 되기전에 내용만 이메일로 보내주면 되는거니 useRef를 사용했다.
const HttpError = require("../error/http-error");
const nodeMailer = require("nodemailer");
const sendEmail = async (req, res, next) => {
const { email, subject, message } = req.body;
try {
const transporter = await nodeMailer.createTransport({
host: "smtp.gmail.com",
port: 587,
secure: false,
auth: {
user: process.env.GMAIL_USER,
pass: process.env.APP_PASS,
},
});
let mailOptions = {
from: email, //송신할 이메일
to: "brgndy96@gmail.com", //수신할 이메일
subject: subject,
html: message,
};
await transporter.sendMail(mailOptions);
} catch (err) {
const error = new HttpError("이메일을 보내는데 실패 했어요!", 503);
return next(error);
}
res.json({ message: "이메일 전송이 완료 되었어요!" });
};
exports.sendEmail = sendEmail;
이메일이 정상적으로 전송되었다.