I'm creating a contact form, and attempting to setState for each field, then pass that value to an email form.
When I console.log, I'm not getting any output. What am I doing wrong here?
Should I be using useEffect? From what I understand, useEffect is called whenever I set state, so I shouldn't need to. Is there something else I'm missing or doing wrong?
import style from "../styles/Contact.module.css";
import React, { useState } from 'react'
export default function Contact() {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [subject, setSubject] = useState('')
const [message, setMessage] = useState('')
const [errors, setErrors] = useState({})
const [buttonText, setButtonText] = useState('Submit')
const [showSuccessMessage, setShowSuccessMessage] = useState(false)
const [showFailureMessage, setShowFailureMessage] = useState(false)
const handleValidation = () => {
let tempErrors = {}
let isValid = true
setName(document.getElementById('name').value)
setEmail(document.getElementById('email').value)
setSubject(document.getElementById('subject').value)
setMessage(document.getElementById('message').value)
console.log(name, email, subject, message)
if (name.length <= 0) {
tempErrors['name'] = true
isValid = false
}
if (email.length) {
tempErrors['email'] = true
isValid = false
}
if (subject.length) {
tempErrors['subject'] = true
isValid = false
}
if (message.length <= 0) {
tempErrors['message'] = true
isValid = false
}
setErrors({ ...tempErrors })
console.log('errors', errors)
return isValid
}
const handleSubmit = async (e) => {
e.preventDefault()
let isValidForm = handleValidation()
if (isValidForm) {
setButtonText('Sending')
const res = await fetch('/api/sendgrid', {
body: JSON.stringify({
email: email,
name: name,
subject: subject,
message: message
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
})
const { error } = await res.json()
if (error) {
console.log(error)
setShowSuccessMessage(false)
setShowFailureMessage('Error, please complete all sections')
setButtonText('Submit')
console.log('success is ', showSuccessMessage)
console.log('failure is ', showFailureMessage)
return
}
setShowSuccessMessage('Contact form submitted')
setShowFailureMessage(false)
console.log('success is ', showSuccessMessage)
console.log('failure is ', showFailureMessage)
setButtonText('Send')
}
console.log(name, email, subject, message)
}
return (
<div className={style.container}>
<h1 className={style.title}>Get in Touch</h1>
<form className={style.form}>
<input className={style.inputS} type="text" placeholder="Name" id='name' />
<input className={style.inputS} type="text" placeholder="Phone" id='phone' />
<input className={style.inputL} type="text" placeholder="Email" id='email' />
<input className={style.inputL} type="text" placeholder="Subject" id='subject' />
<textarea
className={style.textArea}
type="text"
rows={6}
placeholder="Message"
id='message'
/>
<button className={style.button} onClick={handleSubmit}
>{buttonText}
</button>
<p className='error' >
{showSuccessMessage}
{showFailureMessage}
'test'
</p>
</form>
</div>
);
}
Set state is an asynchronous operation, so log the state after setting it, will log the old value.
If you want to sure that the value has been setten correctly, you need to use setState.
setShowSuccessMessage('Contact form submitted')
setShowFailureMessage(false)
setShowSuccessMessage(prev => {
console.log(prev)
return prev
})// log the 'Contact form submitted'
setShowFailureMessage(prev => {
console.log(prev)
return prev
})// log false
And setting state, in this case, will not make the component re-render as you return the same value.
The reason is that setXxx methods are async. If you click submit 10 times fast enough, you will see different results.
You have two options:
not preferred: If you don't use 'controlled' input (you are not using it now - in input elements, you are not using things like 'value={name}'). then you don't need the state at all.
Use controlled input. You can check document on reactjs org.
Simply put,
useState
on the input tag, add value={name} onChange={changeHandler},
in changHandler, setState
in formSubmit, use the value in state
There is a section on forms on this excellent tutorial:
Bob Ziroll free React Course
You are using react so you need to set data and use those data after that i have updated your code it should work for you. i.e. you need to set value in onChange function as below:-
import style from "../styles/Contact.module.css";
import React, { useState } from 'react'
const style = {};
export default function Contact() {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [subject, setSubject] = useState('')
const [message, setMessage] = useState('')
const [errors, setErrors] = useState({})
const [buttonText, setButtonText] = useState('Submit')
const [showSuccessMessage, setShowSuccessMessage] = useState(false)
const [showFailureMessage, setShowFailureMessage] = useState(false)
const handleValidation = () => {
let tempErrors = {}
let isValid = true
console.log(name, email, subject, message)
if (name.length <= 0) {
tempErrors['name'] = true
isValid = false
}
if (email.length) {
tempErrors['email'] = true
isValid = false
}
if (subject.length) {
tempErrors['subject'] = true
isValid = false
}
if (message.length <= 0) {
tempErrors['message'] = true
isValid = false
}
setErrors({ ...tempErrors })
console.log('errors', errors)
return isValid
}
const handleSubmit = async (e) => {
e.preventDefault()
let isValidForm = handleValidation()
if (isValidForm) {
setButtonText('Sending')
const res = await fetch('/api/sendgrid', {
body: JSON.stringify({
email: email,
name: name,
subject: subject,
message: message
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
})
const { error } = await res.json()
if (error) {
console.log(error)
setShowSuccessMessage(false)
setShowFailureMessage('Error, please complete all sections')
setButtonText('Submit')
console.log('success is ', showSuccessMessage)
console.log('failure is ', showFailureMessage)
return
}
setShowSuccessMessage('Contact form submitted')
setShowFailureMessage(false)
console.log('success is ', showSuccessMessage)
console.log('failure is ', showFailureMessage)
setButtonText('Send')
}
console.log(name, email, subject, message)
}
return (
<div className={style.container}>
<h1 className={style.title}>Get in Touch</h1>
<form className={style.form}>
<input className={style.inputS} type="text" placeholder="Name" id='name' onChange={(e) => setName(e.target.value)} />
<input className={style.inputS} type="text" placeholder="Phone" id='phone' />
<input className={style.inputL} type="text" placeholder="Email" id='email' onChange={(e) => setEmail(e.target.value)} />
<input className={style.inputL} type="text" placeholder="Subject" id='subject' onChange={(e) => setSubject(e.target.value)} />
<textarea
className={style.textArea}
type="text"
rows={6}
placeholder="Message"
id='message'
onChange={(e) => setMessage(e.target.value)}
/>
<button className={style.button} onClick={handleSubmit}
>{buttonText}
</button>
<p className='error' >
{showSuccessMessage}
{showFailureMessage}
'test'
</p>
</form>
</div>
);
}
And if you want same for phone you can also set data for the same and use after that.
Related
const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
setIsSubmit(true);
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
);
I'm trying to use axios to do POST method for creating user.
I got everything works fine but there's one small problem but I don't know how to fix.
The problem is that I always need to submit the form 2 times to make the POST request. There's nothing happen in the first submit, but it will work in the second submit.
Does anyone know what's wrong with my code?
Edited
According to #DBS solution.
I'm trying to follow the steps but now the form can't submit anymore. Can someone let me know if I missed something?
const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
if (!Object.keys(formErrors).length && !isSubmitting) {
setFormErrors(validate(formValues));
} else {
userCreate();
setisSubmitting(true);
}
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={handleSubmit}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
<
The issue here is your isSubmit, it is required to be true for userCreate to be called:
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
But it starts as false:
const [isSubmit, setIsSubmit] = useState(false);
And is only ever updated when handleSubmit is called (which, confusingly, is only called when the validation fails)
So your current code does this:
isSubmit is false
Submit is clicked, handleSubmit is called and isSubmit is set to true
Submit is clicked again, now isSubmit is true it will call userCreate
To solve this, there are a few different approaches, but I would:
Move all the submit handler logic into onSubmit={handleSubmit} (To keep things clear)
Inside there, do your error length check (0 error) and isSubmit (Which I would probably rename to isSubmitting for clarity, and make sure it's false) (E.g. !Object.keys(formErrors).length && !isSubmitting)
If there are errors, show the appropriate message (Leaving isSubmitting as false)
If not, call userCreate (And set isSubmitting to true)
Lastly, if this can be submitted multiple times, add an effect/callback/then to reset isSubmitting once the call is complete.
Are you using the isSubmitting flag for something? if not below might be work for you.
If there is no error, calling the create method
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
userCreate();
}
};
if isSubmitting is used to check the submit or create in progress
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
setIsSubmitting(true);
userCreate();
}
};
The flag isSubmitting should be set as false on API is success or failed
setIsSubmitting(false)
I have a formik form with a select field; two options. When i use onClick I always get "yes" submitted and if i use onChange it does not work in that it does not allow me to choose anything, just always leaves the field the same as before.
I have read a ton of different things. I have tried the setFieldValue, and I have tried onBlur, I have tried numerous different ways in writing the onChange handler without any success. Maybe i am just not changing and writing it properly.
I have looked over the suggested questions already on here and for whatever reason i can not get them to work in my code.
import React, { useState, useRef } from 'react';
import { Form, Field, } from 'formik';
import emailjs from '#emailjs/browser';
const RsvpForm = ({ errors, touched, isValid, dirty }) => {
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
const userName = e.target[0].value;
const email = e.target[1].value;
const attending = state;
const plusOne = plusone;
const guests = e.target[4].value;
const guestNumber = e.target[5].value;
const guest_name = e.target[6].value;
const song = e.target[7].value;
const message = e.target[8].value;
let templateParams = {
userName: userName,
email: email,
attending: attending,
plusOne: plusOne,
guests: guests,
guestNumber: guestNumber,
guest_name: guest_name,
song: song,
message: message,
};
emailjs.send(process.env.REACT_APP_SERVICE_ID, process.env.REACT_APP_TEMPLATE_ID, templateParams, process.env.REACT_APP_PUBLIC_KEY)
.then((result) => {
console.log(result.text);
e.target.reset();
}, (error) => {
console.log(error.text);
});
};
const[state, attendingState] = useState("");
const onClick = (e) => {
let{value} = e.target;
if(value=== 'yes') {
attendingState('yes')
}else {
attendingState('no')
}
}
const[plusone, plusOnestate] = useState("");
const onPick = (e) => {
let{value} = e.target;
if(value=== 'no') {
plusOnestate('no')
}else {
plusOnestate('yes')
}
}
return (
<div className='form-group'>
<label className='col-form-label'>Plus One:</label>
<Field
component='select'
className={
touched.plusOne
? `form-control ${errors.plusOne ? 'invalid' : 'valid'}`
: `form-control`
}
name='plusOne'
type='select'
// onChange={(e) => setFieldValue('plusOne', e.target.value)}
onClick={onPick}
>
<option value="">Please select an answer</option>
<option value="yes">Yes, please add a plus one or few</option>
<option value="no">Just me!</option>
</Field>
{touched.plusOne && errors.plusOne && (
<small className='text-warning'><strong>{errors.plusOne}</strong></small>
)}
</div>
I'm trying to have the user input multiple "themes" via a form input bar so that I can add it to the database. The schema model I have created for the object has the "theme" as an array so that part's done. I'm wondering if there's a way to add multiple input values to the same state variable theme in the code down below.
Here is what my code looks like:
import { useState } from "react";
const ProjectAdminForm = () => {
const [sdg, setSDG] = useState('')
const [goal, setGoal] = useState('')
const [orginization, setOrginization] = useState('')
const [source, setSource] = useState('')
const [location, setLocation] = useState('')
const [published, setPublished] = useState('')
const [website_url, setWebsiteURL] = useState('')
const [assignment_type, setAssignmentType] = useState('')
const [theme, setTheme] = useState('')
const [sharepoint_link, setSharepointLink] = useState('')
const [statement, setStatement] = useState('')
const [error, setError] = useState(null)
const handleSubmit = async (e) => {
e.preventDefault() // Prevents refresh of page from happening
console.log('button clicked')
const project = {sdg, goal, orginization, source, location, published, website_url, assignment_type, theme, sharepoint_link, statement}
console.log(project)
// Sending form response to backend
const response = await fetch('/api/projects', {
method: 'POST',
body: JSON.stringify(project),
headers: {
'Content-Type': 'application/json'
}
})
const json = await response.json
// Checking for error
if (!response.ok) {
setError(json.error)
}
if (response.ok) {
// Reset form inputs back to empty string
setSDG('')
setGoal('')
setOrginization('')
setSource('')
setLocation('')
setPublished('')
setWebsiteURL('')
setAssignmentType('')
setTheme('')
setSharepointLink('')
setStatement('')
setError(null)
console.log('new project added', json)
}
}
return (
<form className="create" onSubmit={handleSubmit}>
<h3>Add a New Project</h3>
<label>SDG (Num + Name):</label>
<input
type="text"
placeholder="e.g. SDG 2: Zero Hunger"
onChange={(e) => setSDG(e.target.value)}
value={sdg}
/>
<label>Goal:</label>
<input
type="text"
onChange={(e) => setGoal(e.target.value)}
value={goal}
/>
<label>Orginization:</label>
<input
type="text"
onChange={(e) => setOrginization(e.target.value)}
value={orginization}
/>
<label>Source:</label>
<input
type="text"
onChange={(e) => setSource(e.target.value)}
value={source}
/>
<label>Location:</label>
<input
type="text"
onChange={(e) => setLocation(e.target.value)}
value={location}
/>
<label>Published:</label>
<input
type="text"
onChange={(e) => setPublished(e.target.value)}
value={published}
/>
<label>Website URL:</label>
<input
type="text"
onChange={(e) => setWebsiteURL(e.target.value)}
value={website_url}
/>
<label>Assignment Type:</label>
<input
type="text"
onChange={(e) => setAssignmentType(e.target.value)}
value={assignment_type}
/>
<label>Theme:</label>
<input
type="text"
onChange={(e) => setTheme(e.target.value)}
value={theme}
/>
<label>Sharepoint Link:</label>
<input
type="text"
onChange={(e) => setSharepointLink(e.target.value)}
value={sharepoint_link}
/>
<label>Statement:</label>
<input
type="text"
onChange={(e) => setStatement(e.target.value)}
value={statement}
/>
<button>Add Project</button>
{error && <div className="error">{error}</div>}
</form>
)
}
export default ProjectAdminForm
Specifically for the theme input:
<label>Theme:</label>
<input
type="text"
onChange={(e) => setTheme(e.target.value)}
value={theme}
/>
, how can I have multiple inputs that link to the same theme state which holds them all as an array and then gets passed on to the backend via handleSubmit? Say a user wants to enter "magic", "joy", and "fun" as the themes, how could I make it so that all 3 of those get stored in the theme state variable via the input form?
As array:
//initialise an empty array as the default state for adding themes
const [themes, setThemes] = useState([]);
//create an array to hold your theme names
const available_themes = ['magic', 'joy', 'fun', 'more'];
//create a function for adding themes to your state array
const addTheme = (name) =>{
//if the theme to be added does not exists in the array
if(!themes.includes(name)){
//make a copy (...) of the current themes, and add your new theme name to a new array
setThemes([...themes, name])
}
}
//create a function for removing items from the array
const removeTheme = (name) =>{
//get the index (position) of the theme name in the current state array
const index = themes.indexOf(name);
//if the item exists in the themse array(has an index, is not -1)
if(index !== -1) {
//copy the current array to a tempory data store
let temp_themes = [...themes];
//remove the item from the array using its index
temp_themes.splice(index, 1);
//now save the new array to your state variable of themes
setThemes(temp_themes);
}
}
//for each available theme name create a check box
const themeselector = available_themes.map((name)=>{
//we check if the check box needs to be set to checked, i.e. selected
let checked = false;
//if the current theme is in the theme array it should be selected
if(themes.includes(name)){
checked = true;
}
// we add the checked=checked property {checked: 'checked'} to the check box if the list item should be checked using {...(checked ? {checked: 'checked'}: {})} where (boolean ? on true : else on false )
//we get the ev.target.checked variable to see if the check box has been selected or deselected. We either addTheme, or removeTheme based upon the value of teh variable.
return <div><input type="checkbox" {...(checked ? {checked: 'checked'}: {})} value={name} onClick={(ev)=>{ if(ev.target.checked) { addTheme(name) } else { removeTheme(name)} } } /> {name}</div>;
});
As object:
const [themes, setThemes] = useState({});
const available_themes = ['magic', 'joy', 'fun', 'more'];
const addTheme = (name) =>{
if(typeof themes[name] == 'undefined') {
let temp_themes = {...themes};
temp_themes[name] = name;
setThemes(temp_themes);
}
}
const removeTheme = (name) =>{
if(typeof themes[name] !== 'undefined') {
let temp_themes = {...themes};
delete temp_themes[name];
setThemes(temp_themes);
}
}
const themeselector = available_themes.map((name)=>{
let checked = false;
if(typeof themes[name] !== 'undefined'){
checked = true;
}
return <div><input type="checkbox" {...(checked ? {checked: 'checked'}: {})} value={name} onClick={(ev)=>{ if(ev.target.checked) { addTheme(name) } else { removeTheme(name)} } } /> {name}</div>;
});
<label>Select Themes</label>
{themeselector}
You could do something like this, I guess:
const [theme, setTheme] = useState([''])
And then define a function addTheme that would call setTheme and add a string if it's not already present in the array.
function addTheme(newTheme){
if(!theme.includes(newTheme){
setTheme([...theme, newTheme])
}
}
If you want to use a single text input, one could just create a new array with the values:
const [themes, setThemes] = useState([]);
const [themeText, setThemeText] = useState("");
onSubmit(e) {
e.preventDefault();
setThemes(themeText.split(" "));
}
<label>Theme:</label>
<input
type="text"
onChange={(e) => setThemeText(e.target.value)}
value={themeText}
/>
In React, I have a textbox with a Submit button that is visible when the user clicks 'Wave At Me' and is not visible after the user clicks 'Submit'. What do I put for value in the input tag? How do I get value should I can use it in the setFormText method? In the component class, value is below, but what is the equivalent for the function code?
<input type="text" value={this.state.value} onChange={this.handleChange} />
My code is below in the default App() function, currently the user is unable to change the text:
const [currentVisibility, setVisibility] = useState(false);
const [currentFormText, setFormText] = useState("");
//wave at me button just shows the form
const wave = async () => {
setVisibility(true);
console.log("form appears")
}
// I don't think it's correct to use changeValue function
const changeValue = async () => {
console.log("formed had some text");
}
const handleChange = async () => {
console.log("form was changed");
}
//the handle submit should read the value from the input field to use in the parameter string of the wave() function.
const handleSubmit = async () => {
try {
setVisibility(false);
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
//change to currentText instead of water bottle
const waveTxn = await wavePortalContract.wave("water bottle");
console.log("Mining...", waveTxn.hash);
await waveTxn.wait();
console.log("Mined -- ", waveTxn.hash);
count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
} else {
console.log("Ethereum object does not exist!");
}
} catch (error) {
console.log(error)
}
}
return {currentVisibility && (
<form onSubmit={handleSubmit}>
<label>
Message:
<input type="text" value="" onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
)}
The useState hook returns the state value and a setter function. So in your case, currentFormText is the state value and setFormText is the setter function. Thus, your input should read:
<input type="text" value={currentFormText} onChange={handleChange} />
If you do this, you'll notice you can't change the input's value. That's because React is now "controlling" the value of the input; in other words, React is now the "source of truth" for this input (rather than the browser/HTML itself). Because of this, you'll need to add to your handler function:
// we certainly don't need the `async` keyword here!
const handleChange = (event) => {
console.log("form was changed");
setFormText(event.target.value);
}
On form submit refresh the page, you need to put this code e.preventDefault(); in handleSubmitfunction !
When handleChange function call you need to set the input value in currentFormText state that's why you unable to change the text !
Try this code it's work for me
function App() {
const [currentVisibility, setVisibility] = useState(true);
const [currentFormText, setFormText] = useState("");
//wave at me button just shows the form
const wave = async () => {
setVisibility(true);
console.log("form appears")
}
const changeValue = async () => {
console.log("formed had some text");
}
const handleChange = async (value) => {
setFormText(value)
console.log("form was changed");
}
//the handle submit should read the value from the input field to use in the parameter string of the wave() function.
const handleSubmit = async (e) => {
try {
e.preventDefault();
setVisibility(false);
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
//change to currentText instead of water bottle
const waveTxn = await wavePortalContract.wave("water bottle");
console.log("Mining...", waveTxn.hash);
await waveTxn.wait();
console.log("Mined -- ", waveTxn.hash);
count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
} else {
console.log("Ethereum object does not exist!");
}
} catch (error) {
console.log(error)
}
}
return (
currentVisibility &&
<form onSubmit={(e) => handleSubmit(e)}>
<label>
Message:
<input type="text" value={currentFormText} onChange={(e) => handleChange(e.target.value)} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
export default App;
So I've Managed to made an html form for my react app. The problem is that I cannot output on my console log the inputs on my form. it just shows me this:
Console Log Output Pic
Here is my code snippet:
import { useState } from "react";
const InputForm = (props) => {
const [inputData, setInputData] = useState(
{
enteredFName: "",
enteredLName: "",
enteredEmail: "",
enteredEid: "",
enteredBirthday: "",
},
[]
);
//First Name Validation
const [enteredFName, setEnteredFName] = useState("");
const [enteredFNameTouch, setEnteredFNameTouch] = useState(false);
const enteredFNameFilled = enteredFName.trim() !== "";
const enteredFNameNotFilled = !enteredFNameFilled && enteredFNameTouch;
const enteredFNameValid = /^[A-Za-z\s]+$/.test(enteredFName);
const enteredFNameInvalid = !enteredFNameValid && enteredFNameNotFilled;
const fNameChangeHandler = (event) => {
setEnteredFName(event.target.value);
};
const fNameBlurHandler = () => {
setEnteredFNameTouch(true);
};
//Last Name Validation
const [enteredLName, setEnteredLName] = useState("");
const [enteredLNameTouch, setEnteredLNameTouch] = useState(false);
const enteredLNameFilled = enteredLName.trim() !== "";
const enteredLNameNotFilled = !enteredFNameFilled && enteredLNameTouch;
const enteredLNameValid = /^[A-Za-z\s]+$/.test(enteredLName);
const enteredLNameInvalid = !enteredLNameValid && enteredLNameNotFilled;
const lNameChangeHandler = (event) => {
setEnteredLName(event.target.value);
};
const lNameBlurHandler = () => {
setEnteredLNameTouch(true);
};
//EmailValidation
const [enteredEmail, setEnteredEmail] = useState("");
const [enteredEmailTouch, setEnteredEmailTouch] = useState(false);
const enteredEmailFilled = enteredEmail.trim() !== "";
const enteredEmailNotFilled = !enteredEmailFilled && enteredEmailTouch;
const enteredEmailValid = enteredEmail.includes("#");
const enteredEmailInvalid = !enteredEmailValid && enteredEmailNotFilled;
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const emailBlurHandler = () => {
setEnteredEmailTouch(true);
};
//EIDValidation
const [enteredEid, setEnteredEid] = useState("");
const [enteredEidTouch, setEnteredEidTouch] = useState(false);
const enteredEidFilled = enteredEid.trim() !== "";
const enteredEidNotFilled = !enteredEidFilled && enteredEidTouch;
const eidChangeHandler = (event) => {
setEnteredEid(event.target.value);
};
const eidBlurHandler = () => {
setEnteredEidTouch(true);
};
//Birthday Validation
const [enteredBirthday, setEnteredBirthday] = useState("");
const [enteredBirthdayTouch, setEnteredBirthdayTouch] = useState(false);
const enteredBirthdayFilled = enteredBirthday.trim() !== "";
const enteredBirthdayNotFilled =
!enteredBirthdayFilled && enteredBirthdayTouch;
const birthdayChangeHandler = (event) => {
setEnteredBirthday(event.target.value);
};
const birthdayBlurHandler = () => {
setEnteredBirthdayTouch(true);
};
let formValid = false;
if (
enteredFNameFilled &&
enteredLNameFilled &&
enteredEmailFilled &&
enteredEidFilled &&
enteredBirthdayFilled
) {
formValid = true;
}
const formSubmitHandler = (event) => {
event.preventDefault();
if (!enteredFNameValid || !enteredLNameValid) {
alert("First Name and Last Name accepts letters only.");
return;
}
console.log(inputData);
setEnteredFName("");
setEnteredFNameTouch(false);
setEnteredLName("");
setEnteredLNameTouch(false);
setEnteredEmail("");
setEnteredEmailTouch(false);
setEnteredEid("");
setEnteredEidTouch(false);
setEnteredBirthday("");
setEnteredBirthdayTouch(false);
};
return (
<form onSubmit={formSubmitHandler}>
<div>
<h1>Please Enter your details below</h1>
</div>
<div className="control-group">
<div>
<label>First Name</label>
<input
type="text"
required
id="fName"
onChange={fNameChangeHandler}
onBlur={fNameBlurHandler}
value={enteredFName}
/>
{enteredFNameInvalid && <p>First Name is required.</p>}
</div>
<div>
<label>Last Name</label>
<input
type="text"
required
id="lName"
onChange={lNameChangeHandler}
onBlur={lNameBlurHandler}
value={enteredLName}
/>
{enteredLNameInvalid && <p>Last Name is required.</p>}
</div>
</div>
<div>
<label>Email</label>
<input
type="email"
required
id="email"
onChange={emailChangeHandler}
onBlur={emailBlurHandler}
value={enteredEmail}
/>
{enteredEmailInvalid && <p>Email is required.</p>}
</div>
<div>
<label>EID</label>
<input
type="number"
required
min="1"
step="1"
id="eid"
onChange={eidChangeHandler}
onBlur={eidBlurHandler}
value={enteredEid}
/>
{enteredEidNotFilled && <p>EID is required.</p>}
</div>
<div>
<label>Birthday</label>
<input
type="date"
required
id="birthday"
onChange={birthdayChangeHandler}
onBlur={birthdayBlurHandler}
value={enteredBirthday}
/>
{enteredBirthdayNotFilled && <p>Birthday is required.</p>}
</div>
<div>
<button type="submit" disabled={!formValid}>
Submit
</button>
</div>
</form>
);
};
export default InputForm;
How do I utilize the setInputData for my overall form submission? because I don't know where to put it on the code.
I don't think you need the inputData state, since all your values are already saved in other state variables.
Can you try to console log the following in your formSubmitHandler:
console.log({
enteredFName,
enteredLName,
enteredEmail,
enteredEid,
enteredBirthday,
})
If you insist on keeping the separate state object for submitted values, you can just replace the console.log by setInputData in formSubmitHandler:
setInputData({
enteredFName,
enteredLName,
enteredEmail,
enteredEid,
enteredBirthday,
}
First of all , If you have multi form in your react project, try to use your own hook or use react form hook or formik to make it easier and lower code , its better to get object from Form and pass it like this :
setInputData(data)
If is not possible , set each property in setInputData, and if you have a lot of state , try to write dynamic handler function instead of function for each item , like this :
function handle(type,value){
useState(prev => {
...prev,
[type]:value
})
}