Создание контактной формы с помощью Next.js и Nodemailer


Введение

Существует множество пакетов, которые помогут вам реализовать функциональность электронной почты на вашем сайте или в приложении. Я использовал популярную библиотеку nodemailer, и она очень хорошо сочетается с маршрутами api Next.js.

Я начну с описания компонента контактной формы. Затем я расскажу о том, как я реализовал конечную точку API для обработки запросов электронной почты. Наконец, я завершу статью интеграцией формы с конечной точкой.

Чтобы получить максимальную пользу от этой статьи, вы должны быть знакомы с Javascript, React и Next.js. Давайте начнем с рассмотрения компонента контактной формы, приведенного ниже.

import useContactForm from '../hooks/useContactForm';

const ContactForm = () => {

  const {values, handleChange} = useContactForm();

  const handleSubmit = (e) => {
    e.preventDefault()
  }

  return (
      <form onSubmit={handleSubmit}>
          <label htmlFor='email'>Email</label>
          <input
              required
              id='email'
              value={values.email}
              onChange={handleChange}
              type='email'
          />

          <label htmlFor='subject'>Subject</label>
          <input
              required
              id='subject'
              value={values.subject}
              onChange={handleChange}
              type='text'
          />
          <label htmlFor='message'>Message</label>
          <textarea
              required
              value={values.message}
              onChange={handleChange}
              id='message'
              rows={8}
          />
        <button type='submit' value='Submit'>Send</button>
      </form>
  );
};

export default ContactForm;
Вход в полноэкранный режим Выход из полноэкранного режима

Компонент формы

Компонент формы относительно прост, но давайте разберем, что здесь происходит.

Во-первых, мы импортируем пользовательский хук useContactForm (подробнее об этом позже). Затем мы деструктурируем values и handleChange. Объект values представляет текущее состояние входов формы и имеет следующие свойства и начальное состояние.

const values = {
    email: '',
    subject: '',
    message: '',
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Мы также получаем функцию handleChange, которая будет обрабатывать события формы onChange.

Двигаясь вниз в теле функции, мы получаем функцию handleSubmit для обработки событий формы onSubmit.
В настоящее время единственное, что она делает, это предотвращает отправку формы по умолчанию. Мы добавим больше логики для обработки данных формы позже. А пока давайте подробнее рассмотрим наш пользовательский хук useContactForm.

import {useState} from 'react';

const useContactForm = () => {
  const [values, setValues] = useState({
    email: '',
    subject: '',
    message: '',
  });

  const handleChange = (e) => {
    setValues(prevState => {
      return {
        ...prevState,
        [e.target.id]: e.target.value,
      };
    });
  };

  return {values, handleChange};
};

export default useContactForm;
Вход в полноэкранный режим Выход из полноэкранного режима

Как упоминалось ранее, начальное состояние объекта values содержит свойства, определяемые идентификатором, заданным на форме
input, каждое из которых имеет начальное значение в виде пустой строки.

Функция handleChange обновляет состояние путем включения всех элементов из текущего состояния, используя синтаксис spread. Наконец, мы используем e.target.id для динамического обновления состояния целевого элемента.

Безусловно, существуют и другие способы хранения состояния формы. Наиболее распространенная альтернатива, которая приходит на ум, это использование одного крючка useState для каждого входа формы. Хук useContactForm позволяет нам достичь той же цели, используя меньше кода.

Прежде чем перейти к API, я создал функцию с помощью axios, которую мы будем использовать для
отправки запросов к API.

import axios from 'axios';

const sendEmail = async (email, subject, message) => {
  return axios({
    method: 'post',
    url: '/api/send-mail',
    data: {
      email: email,
      subject: subject,
      message: message,
    },
  });
};

export default sendEmail;
Вход в полноэкранный режим Выход из полноэкранного режима

Мы вернемся к этому, когда будем соединять форму с API.

API

Я создал конечную точку API с помощью встроенных в Next.js Api Routes. Я начал с создания следующей директории
в моем проекте Next.js.

/blog/pages/api
Вход в полноэкранный режим Выход из полноэкранного режима

Я назвал конечную точку send-mail.js. Таким образом, url для конечной точки будет таким:

http://localhost:3000/api/send-mail
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте добавим немного кода в нашу конечную точку.

const nodemailer = require('nodemailer');

export default function handler(req, res) {

  const message = {
    from: req.body.email,
    to: process.env.GMAIL_EMAIL_ADDRESS,
    subject: req.body.subject,
    text: req.body.message,
    html: `<p>${req.body.message}</p>`,
  };

  let transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
      user: process.env.GMAIL_EMAIL_ADDRESS,
      pass: process.env.GMAIL_APP_PASSWORD,
    },
  });

  if (req.method === 'POST') {
    transporter.sendMail(message, (err, info) => {

      if (err) {
        res.status(404).json({
            error: `Connection refused at ${err.address}`
        });
      } else {
        res.status(250).json({
            success: `Message delivered to ${info.accepted}`
        });
      }
    });
  }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Итак, здесь происходит много всего. Во-первых, я включил библиотеку nodemailer. Далее, у нас есть функция handler, которая является обработчиком запроса, с параметрами req и res. Посмотрите документацию по API Routes, если вы не знакомы с
с объектами req и res.

Далее мы создаем объект конфигурации сообщений nodemailer. Я использовал Gmail в качестве
но есть несколько предостережений, которые обсуждаются здесь (использование Gmail).
Отличной новостью является то, что nodemailer поддерживает множество альтернатив. Документация по nodemailer просто фантастическая. Я рекомендую вам ознакомиться с ней, если вы незнакомы с библиотекой.

Мы создаем объект transporter для отправки почтовых данных. Функция transporter принимает данные сообщения и необязательный обратный вызов. Обратный вызов дает нам доступ к объектам error и info, которые я использую для обработки ответа.

Это все для API. Теперь давайте подключим контактную форму.

Подключение формы к api

Добавим остальной код в нашу функцию handleSubmit.

import useContactForm from '../hooks/useContactForm';
import sendEmail from '../lib/sendEmail';
import {useState} from 'react';

const ContactForm = () => {

  const {values, handleChange} = useContactForm();
  const [responseMessage, setResponseMessage] = useState(
      {isSuccessful: false, message: ''});

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const req = await sendEmail(values.email, values.subject, values.message);
      if (req.status === 250) {
        setResponseMessage(
            {isSuccessful: true, message: 'Thank you for your message.'});
      }
    } catch (e) {
      console.log(e);
      setResponseMessage({
        isSuccessful: false,
        message: 'Oops something went wrong. Please try again.',
      });
    }
  };

  return (
      <form onSubmit={handleSubmit}>
          <label htmlFor='email'>Email</label>
          <input
              required
              id='email'
              value={values.email}
              onChange={handleChange}
              type='email'
          />

          <label htmlFor='subject'>Subject</label>
          <input
              required
              id='subject'
              value={values.subject}
              onChange={handleChange}
              type='text'
          />
          <label htmlFor='message'>Message</label>
          <textarea
              required
              value={values.message}
              onChange={handleChange}
              id='message'
              rows={8}
          />
        <button type='submit' value='Submit'>Send</button>
      </form>
  );
};

export default ContactForm;
Вход в полноэкранный режим Выход из полноэкранного режима

Функция handleSubmit преобразуется в асинхронную функцию. Мы используем созданную нами функцию sendEmail для ожидания ответа от новой конечной точки API. Состояние responseMessage обновляется ответом.

Заключение

Теперь, когда состояние responseMessage изменилось, мы можем использовать его для обновления пользовательского интерфейса. Обычно это включает отображение предупреждения для пользователя со статусом сообщения.

Оцените статью
devanswers.ru
Добавить комментарий