0

I am having trouble saving data to a database and then conditionally rendering the components in react.

I want to display a message box, save the message to a database, and then remove the message box and display a thank you message.

For context this is react code in a next.js framework.

User navigates to the contact page at contact/index.js. The default function is

import { useState } from 'react';
import style from '@/styles/general.module.css';

export default function MessageFlow () {

  const [isSubmitted, setSubmitted] = useState(false);
    
    return (
        <>
            {
            isSubmitted ? (
              <p className={style.centerText}>Thank you. We will be in touch.</p>  
            ) : (
              <>
                <Messageform
                  isSubmitted={false}
                  onShow={() => setSubmitted(true)}
                  />     
              </>
            )
          }
        </>
    );
}

In the same file above <Messageflow /> is <Messageform /> which is

function Messageform({ onShow }) {

    return (
      <>
        <h1 className={style.centerText}>
                Contact
        </h1>
           <form onSubmit={handleSubmit}>
               <textarea type="text" id="messageText" className={style.messageBox} placeholder=" General feedback"/>
               <br></br>
               <button type="submit" onClick={onShow} className={style.greenButtonCont}>Submit</button>
           </form>
      </>
    ) 
  }

And above this is handleSubmit as

const handleSubmit = async (note) => {

    note.preventDefault();
    const data = {
        noteData: note.target.messageText.value
    }
    const JSONdata = JSON.stringify(data)
    const endpoint = '/api/messageForm'
    const options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json', 
      }, 
      body: JSONdata,
    }
    await fetch(endpoint, options);
}

So here's the issue: with the code exactly as written, the message box disappears and Thank you. We will be.. appears, but the message is not saved to the database. The error Form submission canceled because the form is not connected contact:1 displays in the browser dev tools.

One answer on S.O. here talks about manipulating the DOM, but React specifically says not to touch the DOM. Also, this is just simple form submission, so I don't think you need to touch the DOM for that.

The other answer here talks about how you should not have an onClick handler on the button where you have type="submit".

I do have an onClick handler on my button that has submit because that is where I update isSubmitted state to true. Updating isSubmitted is what causes the message box to disappear and the Thank you message to appear.

I've tried to update isSubmitted within handleSubmit but this is where it gets complicated.

If I simply pass in isSubmitted like <form onSubmit={handleSubmit(isSubmitted)}> and place setSubmitted(true) within the const handleSubmit = async (note) => .. function then I get a runtime error of

TypeError: note.preventDefault is not a function

I think this is because isSubmitted is not an event object, so you can't do note.preventDefault on that.

I've also tried to destructure the arguments in both the <form .. part and the const handleSubmit = async part and use different combinations such as

<form onSubmit={handleSubmit({ isSubmitted })>
...
const handleSubmit = async ({isSubmitted})

but results ReferenceError: note is not defined.

<form onSubmit={handleSubmit({ isSubmitted })>
...
const handleSubmit = async ({note, isSubmitted})

results TypeError: note.preventDefault is not a function.

Tried dummy variable

<form onSubmit={handleSubmit({ _a, isSubmitted })>
...
const handleSubmit = async ({note, isSubmitted})

results ReferenceError: _a is not defined.

When I delete onClick={onShow} from <button type="submit".. the message does save to my database; but the message box stays there and no thank you message appears.

I tried moving everything to onClick but read that you shouldn't use a button onClick function to submit form data because then you're not able to respond to submit events. I think that's a similar issue when I try to pass in isSubmitted to handleSubmit. It makes note no longer an event.

So how do I save the message, update the state, remove the message box, and then display the thank you message? Seems I need both handleSubmit and onSubmit, but both together is causing the issue.

Krabs
  • 1
  • 1

1 Answers1

0
  1. First issue if you want to pass any arguments to eventHandler function like in your case <form onSubmit={handleSubmit(isSubmitted)}> you are supposed to give just a function name (just handleSubmit without parentheses) and then later when form is submitted event object will be passed to this function. That's why in handleSubmit function expression you accept this argument as note. Or if you want to pass your own arguments you need to do the following <form onSubmit={() => handleSubmit(note, isSubmitted)}> here you are passing an arrow function and not calling it immediately. Then you can use whatever argument you passed in handleSubmit function.

  2. Second issue, you are right you don't need a click handler on the button to update state. State is supposed to be updated only after the message is saved to database. If I understand correctly you can try:

  • remove onClick from the button
  • <form onSubmit={() => handleSubmit(note, onShow)}> pass onShow function to handleSubmit
const handleSubmit = async (note, onShow) => { 
    //saving to db here
    onShow();
    //calling onShow will set Submitted to true;
}
darya
  • 11
  • 1
  • For the record I was able to solve this. I tried to do `
    handleSubmit(note, isSubmitted)}>` but then I had to define `note` within `Messageform` and I didn't know how to define it. The thing about `note` needing to be the event object was tripping me up. I ended up putting everything in one giant component and it worked. Not sure if there is a better way..
    – Krabs Sep 02 '23 at 03:27