DEV Community

Discussion on: How to implement email functionality with Node.js, React.js, Nodemailer, and OAuth2

Collapse
brzezinskibartosz profile image
brzezinskibartosz • Edited on

Hi Jared, thanks for sharing this tutorial. On my website i'm using react hook form. After implementation bigger part of your code, input boxes don't allow me type in anything. For test i didn't set value as {mailerState.yourName} for other inputs. I can send email but it's empty. Please take a look for image in attachment.
Do you know what could be wrong? i'm pasting part of my code. I'll be very grateful for any hint. Cheers!

const { register, handleSubmit, formState: { errors }  } = useForm({
    mode: 'onBlur',
});


const [mailerState, setMailerState] = useState({
    yourName: "",
    email: "",
    phone: "",
    url: "",
    message: "",
});

function handleStateChange(e) {
    setMailerState((prevState) => ({
        ...prevState,
        [e.target.yourName]: e.target.value,
        [e.target.email]: e.target.value,
        [e.target.phone]: e.target.value,
        [e.target.url]: e.target.value,
        [e.target.message]: e.target.value,
    }));
}


const submitEmail = async(e) => {
    e.preventDefault();
    console.log({ mailerState });
    const response = await fetch("http://localhost:3001/send", {
        method: "POST",
        headers: {
            "Content-type": "application/json",
        },
        body: JSON.stringify({ mailerState }),
    })
    .then((res) => res.json())
    .then(async (res) => {
        const resData = await res;
        console.log(resData);
        if (resData.status === "success") {
            console.log("Message Sent");
        } else if (resData.status === "fail") {
            console.log("Message failed to send");
        }
    })
    .then(() => {
        setMailerState({
            yourName: "",
            email: "",
            phone: "",
            url: "",
            message: "",
        });
    });
};


return (
    <ContactsContainer lightBg={lightBg} id='contact'>
        <TextWrapper>
            <TopLine>CONTACTS</TopLine>
            <Heading>Heading</Heading>
            <Subtitle>Text</Subtitle>
        </TextWrapper>
        <form onSubmit={handleSubmit(submitEmail)}>
            <Column1 className="column1">
                <FormGroup className="formGroup">
                    <label className={errors.yourName ? "notok" : "ok"}>Your Name</label>
                    <input className={errors.yourName ? "notok" : "ok"}
                        type="text"
                        onChange={handleStateChange}
                        name="yourName"
                        value={mailerState.yourName}
                        {...register("yourName", { 
                            required: true,
                            minLength: 5 })}
                    />
                    {errors.yourName?.type === 'required' && (<p> 
                        Your name is required.</p>
                    )}
Enter fullscreen mode Exit fullscreen mode
Collapse
jlong4223 profile image
Jared Long Author • Edited on

@brzezinskibartosz
Hey yeah totally. So react-hook-form actually makes things a little easier and requires less code. You actually wont need to specify a handleChange function as react-hook-form will handle that for you & you also wont need the useState hook involved.

Here's a few things you'll need to try:

  • update your input - remove the value & onChange:
 <input
     placeholder="Name"
     name="name"
     {...register("name", { required: true, minLength: 5 })}
  />
Enter fullscreen mode Exit fullscreen mode
  • update your submitEmail function - remove the mailerState being sent and update the parameter name to anything else (named mine data in this example) & e.preventDefault as react-hook-form actually does that for you as well and will throw an error if you leave it. not sure how to reset the values after submitting - youll probably want to check the docs
  async function submitEmail(data) {
    await fetch("http://localhost:3001/send", {
      method: "POST",
      headers: {
        "Content-type": "application/json",
      },
      body: JSON.stringify({ data }),
    })
      .then((res) => res.json())
      .then(async (res) => {
        const resData = await res;
        console.log(resData);
        if (resData.status === "success") {
          alert("Message Sent");
        } else if (resData.status === "fail") {
          alert("Message failed to send");
        }
      });
  }
Enter fullscreen mode Exit fullscreen mode
  • update the API to look for the data being sent in the req instead of mailerState
  let mailOptions = {
    From: `${req.body.data.email}`,
    to: process.env.EMAIL,
    subject: `Message from: ${req.body.data.email} (${req.body.data.name})`,
    text: `${req.body.data.message}`,
  };
Enter fullscreen mode Exit fullscreen mode
Collapse
brzezinskibartosz profile image
brzezinskibartosz • Edited on

Hi Jared, actually i didn't have to change it. Most likely i had bug in handleStateChange function because i declared to many variables.

placeholder="Name"
name="name"
{...register("name", { required: true, minLength: 5 })}
/>

Below 'register' argument i added onChange and value. Everythinhg is working now.

Thanks!
Bartosz

Thread Thread
jlong4223 profile image
Jared Long Author

Nice work, thats great to hear!