How to use setformdata to store data in form - javascript

I'm making a form and below is the format. As you can see I was in two cases (for storing in multistage form) and upon clicking next on the second form we call {onSubmitform}. The problem which you can see is while entering data in form, I'm facing where to store it i.e, {onChange}.
Also ~ please let me know if this was {onSubmitform} will work to send data to the backend.
import React, { useEffect, useState } from 'react';
const Rider_Signup = ()=>{
const [step, setstep] = useState(1);
const [formdata, setFormData] = useState({zipcode:"", email:"",name:"",location:"", dob:"",phone:"",sex:"", password:"",aadhar:""}); // use to hold input from user
const onSubmitform = async e =>{
e.preventDefault();
try{
const email=formdata.email;
console.log(email);
const body={email};
const response = await fetch("http://localhost:5000/api/service/signup",{
method:"POST",headers:{"Content-Type":"application/json"},
body:JSON.stringify(body)
})
const datainjson = await response.json();
window.location =`/driver/login`;
}catch(err){
console.log('Error')
}
}
const renderForm = () =>{
switch(step){
case 1: return <div className="admin_form_div">
<h1 className="form_header">Hey ! </h1>
<center>
<form action="/initial" id="admin_form" name="admin_form">
<label for="Email" className="label">Enter the Email</label><br/>
<input type="email" name="name" className="Email" value={formdata.email} onChange={e =>{console.log(formdata.email)
setFormData(formdata.email=(e.target.value))}} placeholder="email#id.com" pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,}$" title="Please enter valid email" required />
<br/>
<br/>
<button onClick = {() => setstep(step+1)}>Submit</button>
</form>
</center>
</div>
case 2: return <div><h1>{formdata.email} </h1><button onClick = {() => setstep(step+1)}>Submit</button></div>
default: return <div> {onSubmitform}</div>
}
}
return (
renderForm()
)
};
export default Rider_Signup;

formdata is const and cant be reassigned,
formdata can only be changed with setFormData hook.
...formdata will save other fields when only the email is changing.
also, this is duplicated.
onChange={
e => {
console.log(formdata.email)
setFormData({ ...formdata, email: e.target.value })
}
}

Related

Suddenly nothing conditionally rendered works in my react app until after I resave a file

Here's an example of a component I have in my react project:
import {useState, useEffect, useRef} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { createWorker } from '../../actions/worker';
import '../components.scss';
const New = () => {
const [worker, setWorker] = useState(
{
name: "",
email: "",
confirmation_email: "",
admin: false
}
);
const [checked, setChecked] = useState(false); //Determines if admin checkbox is checked or not
const [successMessage, setSuccessMessage] = useState(null); //If there's a success in the uploading process, we simply will put a message at the bottom.
const dispatch = useDispatch();
const errors = useSelector((state) => state.errors.error);
const selectedWorker = useSelector((state) => state.workers.current_worker); //We will be using this to determine if the user has a right to access this page
const renderedAlreadyRef = useRef(false); //Let's us know if we've rendered it already or not
useEffect(() => {
//We'll be using this to see if allWorkers.workers has been updated. We also use the ref renderedAlreadyRef to ensure it only runs after rendering
if (renderedAlreadyRef.current === true && Object.keys(errors).length === 0){
setSuccessMessage("Worker created successfully");
}
}, [errors])
const handleSubmit = (e) => {
//Handles submitting the form
e.preventDefault();
dispatch(createWorker(worker));
renderedAlreadyRef.current = true;
}
const handleChange = (e) => {
const newKey = e.target.id;
const newValue = e.target.value
if (newKey === "admin"){
setChecked(!checked)
setWorker(oldState => ({...oldState, "admin": !checked}))
}
else{
setWorker(oldState => ({ ...oldState, [newKey]: newValue}));
}
}
if (Object.keys(selectedWorker).length !== 0){
if (selectedWorker.admin === 1){
return(
<>
<form id="worker_form" onSubmit={e => handleSubmit(e)}>
<label>
Worker Name:
<input type="text" defaultValue={worker.name} id="name" onChange={e => handleChange(e)}></input>
</label>
<label>
Worker Email:
<input type="text" defaultValue={worker.email} id="email" onChange={e => handleChange(e)}></input>
</label>
<label>
Confirmation Email:
<input type="text" defaultValue={worker.confirmation_email} id="confirmation_email" onChange={e => handleChange(e)}></input>
</label>
<label>
Are they an admin?: <input type="checkbox" checked={checked} id="admin" onChange={e => handleChange(e)} />
</label>
<button type="submit" onClick={e => handleSubmit(e)} className="submit_new_button">Submit</button>
</form>
<h3 className='new_messages'>{successMessage}</h3>
</>
)
}
else{
return(
<div id="Forbidden">
<h1>Error 403 - Forbidden</h1>
<h2>You do not have access to this page</h2>
</div>
)
}
}
else{
return(<h1>Loading...</h1>)
}
}
export default New;
Up until yesterday, this was working flawlessly, but as of yesterday, suddenly, the things that are conditionally rendered no longer work. They just load forever... That is unless I change something in the file (or even just add a bit of whitespace) and then save that file. Suddenly, the thing that wasn't rendering does (in the case of this component, it's the successMessage that doesn't change). I have no idea what could be causing this as I changed a bunch of things yesterday. If you have any idea please let me know as this is confounding me.
I figured it out. Turns out that using refs was the reason this was happening. I'm assuming that based on the way refs work, it didn't re-render the page after they changed (which I guess makes sense since they don't trigger useEffects either).

POST request working in Postman but not in browser (MongoDB + ReactJS)

I am creating simple form application that will input user data and insert them into MongoDB. I am using Axios for CRUD operations and all operations are working in backend (tested in Postman). When I created frontend part (ReactJS) I managed to display all users and delete them by ID. But POST method for creating new user is not working. I am getting 500 Internal server error.
Also I am using FormData and useState. But when calling handleSubmit() method, FormData is empty.
CreateUser.js
const CreateUser = () => {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const submitHandler = (e) => {
e.preventDefault();
const formData = new FormData();
formData.set("firstName", firstName);
formData.set("lastName", lastName);
formData.set("email", email);
dispatch(createNewUser(formData)); //calling POST function from UserActions.js
};
return (
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Enter your first name"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<input
type="text"
placeholder="Enter your last name"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
<input
type="email"
placeholder="Enter your e-mail"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button className="button" type="submit">
Create
</button>
</form>
);
};
export default CreateUser;
Also I am using Redux for state managment so I have my action setup too.
UserActions.js
export const createNewUser = (userData) => async (dispatch) => {
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const { data } = await axios.post("/api/v1/user/new", userData, config);
dispatch({
payload: data
});
} catch (error) {
console.log(error.response);
}
};
Console will display message that firstName lastName email are empty because their require value is set to true.
const userSchema = new mongoose.Schema({
firstName: {
type: String,
required: [true, "Please enter your first name"],
}.....
module.exports = mongoose.model("User", userSchema);
But when I am using console.log() to check their values on input, that works fine. Only passing those values to formData is not working. Or am I missing something else ?
Thanks
TLDR: FormData is empty when trying to submit inserted values to MongoDB while using Axios to POST data

When should I call custom hook not breaking any rules of hooks?

I do have a simple component with form. I want to use useSendEmail hook which returns the server response (success or failure). Where do I call this hook so it doesn't fire on the first render but only after I get my data from the user and save it in the state?
Expected behaviour: hook useSendEmail is called when the email object contains users input and returns status (if sent successfully or not).
I am aware I need to call hook at the top level in the component, but I do I wait for the data from input fields?
Actual behaviour: I am breaking the rule of hooks.
// importing everything I need here
const ContactPage = () => {
const initial = {
from: '',
message: '',
email: '',
};
const [formData, setFormData] = useState(initial);
const [email, setEmail] = useState(null);
const handleChange = ({ name, value }) => {
setFormData({ ...formData, [name]: value });
};
useEffect(() => {
if (email === null) return;
const response = useSendEmail(email);
}, [email]);
const handleSubmit = (e) => {
e.preventDefault();
setEmail(formData);
};
return (
<DefaultLayout title="Contact">
<StyledContainer>
<form className="contact_form" onSubmit={(e) => handleSubmit(e)}>
<input
name="from"
type="text"
value={formData.from}
onChange={(e) => handleChange(e.target)}
placeholder="Your full name"
/>
<textarea
name="message"
value={formData.message}
onChange={(e) => handleChange(e.target)}
placeholder="Your Message"
/>
<input
name="email"
type="email"
value={formData.email}
onChange={(e) => handleChange(e.target)}
placeholder="Your e-mail"
/>
<button type="submit">SUBMIT</button>
</form>
</StyledContainer>
</DefaultLayout>
);
};
export default ContactPage;
EDIT:
this is how my hook looks like after refactoring with your suggestions. I am now importing the hook and the method in the top level component and everything seems to work perfectly.
import { useState } from 'react';
import emailjs from 'emailjs-com';
import { userID, templateID, serviceID } from '../data/account';
const useSendEmail = (email) => {
const [response, setResponse] = useState(null);
const successMsg = 'Your message has been successfully sent';
const errorMsg = 'Your message has not been sent. Try again.';
const sendEmail = async () => emailjs
.send(serviceID, templateID, email, userID)
.then(
(res) => {
if (res.status === 200) {
setResponse(successMsg);
}
if (res.status !== 200) {
setResponse(errorMsg);
}
},
(err) => {
console.log(err);
},
);
return { response, sendEmail }
};
export default useSendEmail;

How do i get the value of text input field using react

I'm creating a register form in react with validation. The values i'm asking is Username, Email, password + (controll password). Everything about the form works, validations, Errors and if you click sign up you go to a new page. Now i want to extract the values to a my MySql database. I succeed in putting stuff in my database so the link works but i can't get the values of what i typed in the form.
I have tried
onChange={(e) => {
setUsernameReg(e.target.value);
}}
(see commented item)
But when i tried this I couldn't fill anything in Username. The code for the other inputs (email, password) is the same apart from the names.
So in short I want to get the value what you typed in a textbox to my database.
Code: FormSignup.js
import React, { useEffect, useState } from 'react';
import Axios from 'axios';
import validate from './validateInfo';
import useForm from './useForm';
import './Form.css';
const FormSignup = ({ submitForm }) => {
const { handleChange, handleSubmit, values, errors } = useForm(
submitForm,
validate
);
const [usernameReg, setUsernameReg] = useState("");
const [emailReg, setEmailReg] = useState("");
const [passwordReg, setPasswordReg] = useState("");
Axios.defaults.withCredentials = true;
const register = () => {
Axios.post("http://localhost:3001/register", {
username: usernameReg,
password: passwordReg,
email: emailReg,
}).then((response) => {
console.log(response);
});
};
return (
<div className='form-content-right'>
<form onSubmit={handleSubmit} className='form' noValidate>
<h1>
Get started with us today! Create your account by filling out the
information below.
</h1>
<div className='form-inputs'>
<label className='form-label'>Username</label>
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={values.username}
onChange={handleChange}
/*
//onChange={(e) => {
// setUsernameReg(e.target.value);
//}}
*/
/>
Code UseForm.js
import { useState, useEffect } from 'react';
import Axios from 'axios';
const useForm = (callback, validate) => {
const [values, setValues] = useState({
username: '',
email: '',
password: '',
password2: ''
});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [usernameReg, setUsernameReg] = useState("");
const [emailReg, setEmailReg] = useState("");
const [passwordReg, setPasswordReg] = useState("");
Axios.defaults.withCredentials = true;
const register = () => {
Axios.post("http://localhost:3001/register", {
username: usernameReg,
password: passwordReg,
email: emailReg,
}).then((response) => {
console.log(response);
});
};
const handleChange = e => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
};
const handleSubmit = e => {
e.preventDefault();
setErrors(validate(values));
setIsSubmitting(true);
};
useEffect(
() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
}
},
[errors]
);
return { handleChange, handleSubmit, values, errors };
};
export default useForm;
The code is from https://www.youtube.com/watch?v=KGFG-yQD7Dw&t and https://www.youtube.com/watch?v=W-sZo6Gtx_E&t
By using the value prop of the input, you turn it into a controled input element and thus need to update its value via a state variable. So this:
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={values.username}
onChange={handleChange}
/*
//onChange={(e) => {
// setUsernameReg(e.target.value);
//}}
*/
/>
Should just be this:
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={usernameReg}
onChange={e => setUsernameReg(e.target.value)}
/>
Note that this only answers this part:
I succeed in putting stuff in my database so the link works but i can't get the values of what i typed in the form
So this is how you can access those values. I can't guide you on how to get those values all the way to your DB as there is a longer distance they have to travel and I don't know what else could be in the way.
You should also look into useRef(), which will give you access to those input fields without updating your state on every change of the input and thus re-rendering your form over and over.
You can do something like this:
...
const regInput = React.useRef();
...
...
<input
ref={regInput}
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
Then when you're ready to submit, just access the value of the username input like so:
...
const v = regInput.current.value;
...

Local storage not updating React

I'm btrying to save an array of objects in local storage, each time a user clicks a button, i add the username and email fron input fields
but it keeps updating the local storage instead of appending new object to the array
Below is my code
const app = () => {
const [allusers,setAllusers] = useState([JSON.parse(localStorage.getItem('users')) || '']);
const [id,setId] = useState(0);
const [newuser,setNewuser] = useState({
'id':id
'name':'David',
'email':'david#gmail.com'
})
const handleChange = () =>{
setNewuser({...newuser,[e.target.name] : e.target.value});
}
const add = ()=>{
setAllusers([newuser])
localStorage.setItem('users',JSON.stringify(allusers))
setID(id+1); // increase id by 1
}
return(
<div>
<form>
<input type="text" name="user" onChange={handleChange}>
<input type="text" name="email" onChange={handleChange}>
<button onclick={()=>save}>Save</button>
</form>
</div>
)
}
export default app;
There were a lot of syntactical errors and use of functions like save which was never declared and still used.
I rewrote the whole example and made it a bit modular so that you can comprehend it better.
Here is the working example:
Final Output:
Full Source code:
import React, { useState, useEffect } from "react";
import "./style.css";
const App = () => {
const [allusers, setAllusers] = useState([]);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleName = e => {
setName(e.target.value);
};
const handleEmail = e => {
setEmail(e.target.value);
};
const save = e => {
e.preventDefault();
let newUsers = {
id: Math.floor(Math.random() * 100000),
name: name,
email: email
};
localStorage.setItem("users", JSON.stringify([...allusers, newUsers]));
setAllusers(allusers.concat(newUsers));
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
};
useEffect(() => {
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
if (localStorage.getItem("users")) {
setAllusers(JSON.parse(localStorage.getItem("users")));
}
}, []);
return (
<div>
<form>
<input type="text" name="user" onChange={handleName} />
<input type="text" name="email" onChange={handleEmail} />
<button onClick={save}>Save</button>
<p>{JSON.stringify(allusers)}</p>
</form>
</div>
);
};
export default App;
As You inquired in the comment section, here is how you can implement the Update functionality:
Final Output:
Full source code:
import React, { useState, useEffect } from "react";
import "./style.css";
const App = () => {
const [allusers, setAllusers] = useState([]);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [id, setId] = useState(null);
const handleName = e => {
setName(e.target.value);
};
const handleEmail = e => {
setEmail(e.target.value);
};
const save = e => {
e.preventDefault();
let newUsers = {
id: Math.floor(Math.random() * 100000),
name: name,
email: email
};
localStorage.setItem("users", JSON.stringify([...allusers, newUsers]));
setAllusers(allusers.concat(newUsers));
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
};
const setForUpdate = user => {
setName(user.name);
setEmail(user.email);
setId(user.id);
};
const update = e => {
e.preventDefault();
let modifiedData = allusers.map(user => {
if (user.id === id) {
return { ...user, name: name, email: email };
}
return user;
});
setAllusers(modifiedData);
localStorage.setItem("users", JSON.stringify(modifiedData));
setId(null);
};
useEffect(() => {
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
if (localStorage.getItem("users")) {
setAllusers(JSON.parse(localStorage.getItem("users")));
}
}, []);
return (
<div>
<form>
<input value={name} type="text" name="user" onChange={handleName} />
<input value={email} type="text" name="email" onChange={handleEmail} />
<button disabled={!(id == null)} onClick={save}>
Save
</button>
<button disabled={id == null} onClick={update}>
Update
</button>
</form>
{allusers &&
allusers.map(user => (
<div className="userInfo">
<p>{user.name}</p>
<p>{user.email}</p>
<button onClick={() => setForUpdate(user)}>
select for update
</button>
</div>
))}
</div>
);
};
export default App;
You can find the working example here: Stackblitz
You are trying to save allusers to the localStorage right after setAllUsers() but setState is asynchronous. The value does not have to be updated on the next line. You can read more about it at reactjs.org, Why is setState giving me the wrong value?.
I would recommend to use useEffect.
const add=()=> {
setAllusers([... allusers ,newuser])
}
useEffect(()=>{
// this is called only if the variable `allusers` changes
// because I've specified it in second argument of useEffect
localStorage.setItem('users',JSON.stringify(allusers))
}, [allusers]);
()=>handleChange is a function that takes no arguments and returns the handleChange function. You probably want () => handleChange(), which would take no arguments and INVOKE handleChange.
you are adding only one new user while clicking on add button. You need to copy previous data also when setting all users.
Second thing setting state is async and hence your localStorage and allusers may have different value and to avoid this one you need to use useEffect to set the value.
const add = ()=>{
setAllusers([...allusers ,newuser])
setID(id+1); // increase id by 1
}
useEffect(() => {
localStorage.setItem('users',JSON.stringify(allusers))
},[allusers])

Categories

Resources