nodemailerとnetlify関数を使用したServerless ReactJSの連絡フォームの構築と配備


ReactJSはクライアント側のJavaScriptフレームワークです.このように、クライアントの機能に直面している負荷の見栄えの良い連絡先を構築することができますが、他の場所には、データベースにエントリを追加する電子メールを送信するなどのバックエンド機能を必要とする何かを行う必要があります.これは私がこのポストで対処する課題です-どのように構築し、提出するときに電子メールを送信するreactjsの連絡先のフォームを展開します.
ツールボックスは以下のようになります:
  • ReactJS (明らかに)
  • Axios (データを投稿する)
  • nodemailer ( Node . jsパッケージがSMTP経由でメールを送信するために使用されます).
  • netlify (配備用)
  • フロントエンドフォームからデータをキャプチャし、バックエンドURLに投稿します.我々はバックエンドとして機能するnetlify関数を構築し、投稿したフォームデータを利用しますNodemailer 受信者にデータをメールする.
    それは本当に簡単に聞こえるように.

    始めましょう.

    フロントエンド


    まず、フロントエンドをreactjsを使ってビルドします.セットアップするには、我々は実行されますnpx create-react-app contact-form 私たちのターミナルウィンドウで.これは我々が変更する標準reactjsアプリを提供します.そして、我々は待ちます..
    ...一度我々の反応アプリがインストールされてnpm start ブラウザでアプリケーションを実行します.オープンsrc/App.js との間のすべてを削除<header> タグは以下のようになります.
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    
    function App() {
      return (
        <div className="App">
        </div>
      );
    }
    
    export default App;
    
    それをしている間、取り除くimport logo from './logo.svg' . ああ、今我々は空白のキャンバス😌.
    では、新しいファイルをsrc ディレクトリ.これはコンタクトフォームモジュールです.私の電話contact-form.js , 何でも好きなものを呼んでいい.反応モジュールの基本構造は以下の通りです.
    import React from 'react'
    
    export default function FunctionName() {
        return (
            ...
        )
    }
    
    
    だから、私たちのコンタクトフォームの構造を構築することから始めることができます.使っているmaterial-us しかし、もう一度、あなたの選択のCSSフレームワークを使用することができます.すべてのことは、フォームがあることです.
    import React from 'react'
    import TextField from "@material-ui/core/TextField";
    import Button from "@material-ui/core/Button"
    import FormControl from "@material-ui/core/FormControl"
    
    export default function Form() {
    
        return (
            <>
    
                <FormControl fullWidth={true}>
                    <TextField required label="Full name" variant="filled" id="full-name" name="name" className="form-field" />
                </FormControl>
                <FormControl fullWidth={true}>
                    <TextField required label="Email" id="email" name="email" variant="filled" className="form-field" onChange />
                </FormControl>
                <FormControl fullWidth={true}>
                    <TextField required label="Message" variant="filled" name="message" multiline={true} rows="10" />
                </FormControl>
                <FormControl>
                    <div style={{padding: 20}}>
                        <Grid container spacing={2}>
                                <div className="form-submit">
                                    <Button variant="contained" color="primary">Submit</Button>
                                </div>
                            </Grid>
                        </Grid>
                    </div>
                </FormControl>
        )
    }
    
    
    今、我々は連絡先フォームをインポートすることができますApp.js . 変更するApp.js 次のようになります.
    import React from 'react';
    import logo from './logo.svg';
    import Form from './contactform'
    import './App.css';
    
    function App() {
      return (
        <div className="App">
          <Form />
        </div>
      );
    }
    
    export default App;
    

    キャプチャフォームデータ


    我々が作る必要があるいくつかの追加があります.まず、フォームデータをキャプチャする必要があります.そして、使用するよりもこれを行う良い方法react hooks - 特にuseState 私たちが追跡し、リアルタイムで我々のデータの'状態'を更新するために使用します.で最初の行を変更するcontactform.js 含めるuseState フック
    import React, { useState } from 'react'
    
    次に、インスタンス化しますuseState 変数.変数は2つの項目ですarray 最初の項目が状態であることを追跡し、2番目の項目がその状態を更新するための関数です.
    export default function Form() {
        const [data, setData] = useState()
    
        return (
            ...
        )
    }
    
    フォームから複数のフィールドをキャプチャする必要があるので、セットアップを行いますdata としてobject :
    export default function Form() {
        const [data, setData] = useState({name: '', email: '', message: '', sent: false, buttonText: 'Submit', err: ''})
    
        return (
            ...
        )
    }
    
    ご覧のように、我々は単にUSENTの初期値を設定することによってこれを行うobject notation . また、私たちのリクエストのステータスを追跡し、ユーザーにフィードバックを提供するいくつかのユーティリティアイテムを設定しますsent , buttonText and err . 後でこれらの上でより多くの.
    今、我々は我々の更新方法を必要とするdata オブジェクト.簡単なPEEasy -私たちは、我々のフォームフィールドへの変更を追跡する機能を設定します
    ...
    
    const [data, setData] = useState({name: '', email: '', message: '', sent: false, buttonText: 'Submit', err: ''})
    
    const handleChange = (e) => {
        const {name, value} = e.target
            setData({
                ...data,
                [name]: value
        })
    }
    
    ...
    
    その名前が示すように、ユーザーがフォームフィールドの一つを変更するたびにこの関数が呼び出されます.この関数は、name and value フォームフィールドの属性を変更し、対応する値をdata オブジェクト.
    我々がする必要がある最後のことはonChange and value ユーザ関数としてこの関数をコールするフォームフィールドの属性
    <FormControl fullWidth={true}>
        <TextField required label="Full name" variant="filled" id="full-name" name="name" className="form-field" value={data.name} onChange={handleChange} />
    </FormControl>
    <FormControl fullWidth={true}>
         <TextField required label="Email" id="email" name="email" variant="filled" className="form-field" value={data.email} onChange={handleChange} />
    </FormControl>
    <FormControl fullWidth={true}>
         <TextField required label="Message" variant="filled" name="message" multiline={true} rows="10" value={data.message} onChange={handleChange} />
    </FormControl>
    <FormControl>
        <div className="form-submit">
            <Button variant="contained" color="primary">Submit</Button>
        </div>
    </FormControl>
    

    ハンドルフォーム


    フォームのサブミッションを扱う関数を設定する必要があります
    const formSubmit = (e) => {
        e.preventDefault()
    } 
    
    我々はpreventDefault デフォルトの動作であるバックエンドURLにユーザーをリダイレクトするフォームを停止する機能.
    私が言ったとき、私たちがpost 我々のバックエンドURLへのデータ?まあそれはどこAxios 入って来る-それは約束ベースのHTTPクライアントであり、完全に我々のニーズを提供します.ランニングでつかむnpm i axios そしていったんインストールされたら、Submit関数を終了できます.
    const formSubmit = (e) => {
            e.preventDefault();
    
            setData({
                ...data,
                buttonText: 'Sending...'
            })
    
            axios.post('/api/sendmail', data)
            .then(res => {
                if(res.data.result !=='success') {
                    setData({
                        ...data,
                        buttonText: 'Failed to send',
                        sent: false,
                        err: 'fail'
                    })
                    setTimeout(() => {
                        resetForm()
                    }, 6000)
                } else {
                    setData({
                        ...data,
                        sent: true,
                        buttonText: 'Sent',
                        err: 'success'
                    })
                    setTimeout(() => {
                        resetForm();
                    }, 6000)
                }
            }).catch( (err) => {
                //console.log(err.response.status)
                setData({
                    ...data,
                    buttonText: 'Failed to send',
                    err: 'fail'
                })
            })
        }
    
    この関数が何をしているかを調べましょう.フォームの既定の動作を防止した後、フォームはbuttonText アイテムdata 送信するオブジェクト.我々は、送信ボタンにテキストを変更し、ユーザーにいくつかのフィードバックを与えるために使用します.
    次に、機能が完璧とaxios.post URLへのリクエストapi/sendmail これは私たちのnetlify関数を呼び出すときに我々はそれを無駄にします.レスポンスが'成功'であるならば、ボタンテキストは『送信に失敗しました』と我々のユーティリティアイテムに変えられますerr '失敗'は後で使用するように設定されます.フォームは、setTimeout 関数.
    レスポンスが'成功'であるならば、ボタンテキストは『送られて』err アイテムは'成功'に変更されました.それから、私たちはどんなリクエスト関連のエラーにも対処しますcatch 条項.
    あなたは、我々が参照することに気がつきますresetForm 関数.ここにあります.
        const resetForm = () => {
            setData({
                name: '',
                email: '',
                message: '',
                sent: false,
                buttonText: 'Submit',
                err: ''
            });
        }
    
    この関数はdata オブジェクトを元の状態に戻します.
    我々は、ちょうど変更する必要がありますonClick を呼び出して、handleSubmit それに応じてボタンテキストを機能し、更新します.
    <Button variant="contained" color="primary" onClick={formSubmit}>{data.buttonText}</Button>
    
    

    Netlify関数


    Netlify functions あなたのアプリケーションのサーバー側の機能を与えるAPIを書くことができます.我々の場合、我々は我々を取る機能を書きますdata オブジェクトとしてpost 要求と使用nodemailer 受信者にメールを送信します.
    まず最初に、私が提案することはnetlifynpm install netlify-cli -g . このwilは私たちのフォームをテストするのに役立ちます.次に、ディレクトリを作成しますfunctions プロジェクトのルートでは(関数'と呼ぶ必要はありません).インfunctions フォルダーと呼ばれるファイルを作成するsendmail.js . 何か我々axios.post リクエスト投稿api/sendmail - ポストロケーションと関数ファイル名が同じである必要があります.
    この時点で、netlify - cliはインストールされていなければなりません.したがって、フリーノードであるNodeDailerのコピーを取得します.JSのモジュールは、彼らの言葉では、ケーキのメール送信として'簡単にできます.誰もがケーキが大好きです.ランnpm install nodemailer .
    インストール中に我々は我々の頭にsendmail.js ファイルを追加し、このコードを追加します
    const nodemailer = require('nodemailer');
    
    exports.handler = function(event, context, callback) {
    
        let data = JSON.parse(event.body)
    
        let transporter = nodemailer.createTransport({
            host:[YOUR SMTP SERVER],
            port:[YOUR SMTP SERVER PORT],
            auth:{
             user:[YOUR SMTP SERVER USERNAME],
             pass: [YOUR SMTP SERVER PASSWORD]
        }
        });
    
        transporter.sendMail({
            from: [YOUR SMTP SERVER EMAIL ADDRESS],
            to: [RECIPIENT EMAIL ADDRESS],
            subject: `Sending with React, Nodemailer and Netlify`,
            html: `
                <h3>Email from ${data.name} ${data.email}<h3>
                <p>${data.message}<p>
                `
        }, function(error, info) {
            if (error) {
                callback(error);
            } else {
                callback(null, {
                statusCode: 200,
                body: JSON.stringify({
                       'result': 'success'
                    })
            });
            }
        });
    }
    
    この関数は何をしていますか.netlify関数はすべて同じ設定であり、documented extensively . 要するに、彼らはhandler メソッドとテイクevent , context and callback パラメータ.我々の場合はevent and callback の定数であるパラメータrequest and response .
    最初に、関数はリクエストを解析しますdata オブジェクト.次の宣言とセットアップtransporter 我々が使用しているSMTP輸送に関連するデータを保持する変数.NodeDailerはSMTPサーバー、ポートと認証されたSMTPトランスポートの認証情報が必要です.使用するZoho mail これは無料ですが、任意のプロバイダを使用することができます.あなたは人気の選択のようだが、Gmailを使用することができますがdocumented issues with using Gmail したがって、別のプロバイダを使用することもできます.
    あなたはもっと読むことができますnodemailer SMTP transport here . があるwell-known SMTP services that work with nodemailer here .
    機能に戻る.一度transporter 変数は設定ですtransporter.sendMail(data[, callback]) メッセージを設定し、メールを送信します.

    リダイレクトの設定


    私たちはこれを実行するためにいくつかの最終ビットを行う必要があります.第一に、我々はnetlify.toml プロジェクトのルートファイル.このファイルはNetLifyのビルド設定を知っています.我々の中でnetlify.toml ファイルに2つの重要な設定を追加します.
    [build]
        functions = "functions"
    [[redirects]]
        from = "/api/*"
        to = "/.netlify/functions/:splat"
        status = 200
    
    一つ目は、我々の関数がfunctions ディレクトリ.シンプル.
    つ目はnetlifyに何かを投稿するように指示するリダイレクトです/api/* この関数は、/.netlify/functions/ ディレクトリ.The :splat キーワードは、マッチのためにnetlifyに言います/api/sendmail//.netlify/functions/sendmail , ルックsendmail ちょうど我々の機能ファイルの名前であることは起こります.それで、我々の掲示されたデータは予想通り我々の機能で終わります.You can read more about Netlify redirects here

    テスト展開


    NetLify CLIをインストールしたので、実行してフォームをテストするのは簡単ですnetlify dev 我々の端末で.これは私たちのコンタクトフォームのローカルコピーを実行します.

    結論


    私は、フォームと同様に基本的な妥当性確認を加えましたreact-google-captcha . すべてのコードをチェックアウトすることができますthis repo . netlify関数の場合、this repo . ここにNetlify機能例のコード断片もたくさんあります.
    フォト・クレジットBrett Jordan on Unsplash