Search code examples
node.jsreactjsaxiosnodemailernetlify

I have a simple react contact me form, the email it is supposed to send from nodemailer is coming in empty


this is my front end code, I think the problem is here. So, when the form is submitted everything that is supposed to work works but the email shows up empty. Also I was getting an error in the console here it is...

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

So, i added that useEffect clean up function although im not sure if i did it right the error is gone. Are these two things related? Somehow the state is not being updated in time. If i hard code the message the email sends out fine. Thank you. Also any additional advice would be cool.

     import React, { useEffect, useState } from 'react';
     import axios from 'axios';


     export default function ContactMe(props) {
     
       const [data, setData] = useState({email: '',phone: '', 
       message: '', sent: false});
       const [thankYouMessage, setThankYouMessage] = useState('');
     
         const goBack = () => {
             props.setIsOnHomePage(true);
         }
     
         const onChange = (e) => {
           const {name, value} = e.target
               setData({
                   ...data,
                   [name]: value
           })
         }
     
         const resetForm = () => {
           setData({
               email: '',
               phone: '',
               message: '',
               sent: false,
           });
         }
     
         // here I think is the problem in this function?
         const onSubmit = (e) => {
           setData({
             ...data,
         })
     
         axios.post('/api/sendmail', data)
     .then(res => {
         if(res.data.result !=='success') {
             setData({
                 ...data,
                 sent: false,
             })
             resetForm();
         } else {
           setData({
               ...data,
               sent: true,
           })
           resetForm();
       }
     }).catch( (err) => {
       setData({
           ...data,
       })
     })
           setThankYouMessage('thank you');
     }
     
        useEffect(() => {
          const source = axios.CancelToken.source()
          return () => {
            source.cancel()
        }
      }, [])
     
     

         return (
                <div className = 'contact-me-form'>
                   <button className = 'go-back' onClick = 
                   {goBack}>go back</button>
                   <h1 className = 'contact-me-title'>Contact 
                    me</h1>
                   <form>
                     <p className = 'input-title'>email</p>
                     <input className = 'input-field' defaultValue 
                      = {data.email} onChange={onChange}></input>
                     <p className = 'input-title' >phone 
                      number</p>
                     <input className = 'input-field' defaultValue 
                      = {data.phone} onChange={onChange}></input>
                     <p className = 'input-title' >message</p>
                     <textarea className = 'text-field' 
                     defaultValue = {data.message} onChange= 
                     {onChange} rows = '3'></textarea>
                   </form>
                   <button onClick = {() => {onSubmit()}} 
                    className = 'submit-contact-form- 
                    button'>submit</button>
                   <p className = 'thank-you-message'> 
                   {thankYouMessage}</p>
                </div>
         )
     }

Solution

  • You need three main changes:

    1. Set name attribute in input/textarea tags;
    2. In onChange handler, get name attribute with e.target.getAttribute("name");
    3. In onSubmit handler, remove setData, because is unecessary;
    import React, { useEffect, useState } from "react";
    import axios from "axios";
    
    export default function ContactMe(props) {
      const [data, setData] = useState({
        email: "",
        phone: "",
        message: "",
        sent: false,
      });
      const [thankYouMessage, setThankYouMessage] = useState("");
    
      const goBack = () => {
        props.setIsOnHomePage(true);
      };
    
      const onChange = (e) => {
        const value = e.target.value;
        const name = e.target.getAttribute("name");
        setData({
          ...data,
          [name]: value,
        });
      };
    
      const resetForm = () => {
        setData({
          email: "",
          phone: "",
          message: "",
          sent: false,
        });
      };
    
      // here I think is the problem in this function?
      const onSubmit = (e) => {
        axios
          .post("/api/sendmail", data)
          .then((res) => {
            if (res.data.result !== "success") {
              setData({
                ...data,
                sent: false,
              });
              resetForm();
            } else {
              setData({
                ...data,
                sent: true,
              });
              resetForm();
            }
          })
          .catch((err) => {
            setData({
              ...data,
            });
          });
        setThankYouMessage("thank you");
      };
    
      useEffect(() => {
        const source = axios.CancelToken.source();
        return () => {
          source.cancel();
        };
      }, []);
    
      return (
        <div className="contact-me-form">
          <button className="go-back" onClick={goBack}>
            go back
          </button>
          <h1 className="contact-me-title">Contact me</h1>
          <form>
            <p className="input-title">email</p>
            <input
              className="input-field"
              defaultValue={data.email}
              name="email"
              onChange={onChange}
            ></input>
            <p className="input-title">phone number</p>
            <input
              className="input-field"
              defaultValue={data.phone}
              name="phone"
              onChange={onChange}
            ></input>
            <p className="input-title">message</p>
            <textarea
              className="text-field"
              defaultValue={data.message}
              name="message"
              onChange={onChange}
              rows="3"
            ></textarea>
          </form>
          <button
            onClick={() => {
              onSubmit();
            }}
            className="submit-contact-form-button">
            submit
          </button>
          <p className="thank-you-message">{thankYouMessage}</p>
        </div>
      );
    }