React-Formik: How to create registeration form using Formik? - reactjs

I am learning React.js and want to use Formik for my project. In backend I've created registration endpoint, which works fine in frontend as well with simple form. I don't know how to implement Formik instead of simple form. I can't move forward, since all the time i get the same error:
Line 121:20: 'firstName' is not defined no-undef
Line 122:19: 'lastName' is not defined no-undef
Line 123:16: 'email' is not defined no-undef
Line 124:19: 'password' is not defined no-undef
How to get rid of that error and make it work?
Here is the register component with default form, which works fine.
import React, { useState } from 'react'
const Register = () => {
const [data, setData] = useState([])
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const saveRegister = () => {
fetch('http://localhost:8000/api/v1/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstName: firstName,
lastName: lastName,
email: email,
password: password,
}),
})
.then((res) => res.json())
.then((result) => {
setData(result)
console.log(result)
})
.catch((err) => console.log('error'))
}
const handleFirstName = (e) => {
setFirstName(e.target.value)
}
const handleLastName = (e) => {
setLastName(e.target.value)
}
const handleEmail = (e) => {
setEmail(e.target.value)
}
const handlePassword = (e) => {
setPassword(e.currentTarget.value)
}
const handleSubmit = (e) => {
e.preventDefault()
saveRegister()
setFirstName('')
setLastName('')
setEmail('')
setPassword('')
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
name="firsName"
onChange={handleFirstName}
value={firstName}
placeholder="firstName"
/>
<input
type="text"
name="lastName"
onChange={handleLastName}
value={lastName}
placeholder="lastName"
/>
<input
type="text"
name="email"
onChange={handleEmail}
value={email}
placeholder="email"
/>
<input
type="text"
name="password"
onChange={handlePassword}
value={password}
placeholder="password"
/>
<button type="submit">signup</button>
</form>
</div>
)
}
export default Register
In here I'm trying to implement Formik instead
import React, { useState } from 'react'
import {
Formik,
Form,
Field,
ErrorMessage,
} from 'formik'
import * as Yup from 'yup'
function Register() {
const [data, setData] = useState([])
const saveRegister = (values) => {
fetch('http://localhost:8000/api/v1/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstName: values.firstName,
lastName: values.lastName,
email: values.email,
password: values.password,
}),
})
.then((res) => res.json())
.then((result) => {
setData(result)
})
.catch((err) => console.log('error'))
}
const initialValues = {
email: '',
lastName: '',
firstName: '',
password: ''
}
const onSubmit = (values, setSubmitting) => {
setSubmitting(true);
console.log(values);
saveRegister(values)
setSubmitting(false)
}
const validationSchema = Yup.object({
firstName: Yup.string().required('Required'),
lastName: Yup.string().required('Required'),
password: Yup.string().required('Required'),
email: Yup.string()
.email('Invalid email format').required('Required'),
})
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
{({ values, isSubmitting }) => (
<Form >
<div>
<label htmlFor='email'>E-mail</label>
<Field
type='text'
id='email'
name='email'
/>
<ErrorMessage name='firstName' />
</div>
<div>
<label htmlFor='firstName'>firstName</label>
<Field
type='text'
id='firstName'
name='firstName'
/>
<ErrorMessage name='lastName' />
</div>
<div>
<label htmlFor='lastName'>lastName</label>
<Field
type='text'
id='lastName'
name='lastName'
/>
<ErrorMessage name='lastName' />
</div>
<div >
<label htmlFor='password'>password</label>
<Field
type='password'
id='password'
name='password'
/>
<ErrorMessage name='password' />
</div>
<button type='submit'>Submit</button>
</Form>
)}
</Formik>
)
}
export default Register

<>
<Formik {{ initialValues, validationSchema, onSubmit }}>
</Formik>
</>
and your on submit method
const onSubmit = (values, setSubmitting) => {
setSubmitting(true);
console.log(values);
saveRegister(values)
setSubmitting(false)
and in your saveRegister
const saveRegister = (values) => {
values.email //and so on
}

Related

handleSubmit to call another function with event parameter

This is React JS.
I had a nice working sendData function that creates a new record on my json file.
It worked nice until I decided to add useForm to add some yup resolvers.
Now in the <form> tag here is onSubmit={}.
If I write here
<form onSubmit={handleSubmit(sendData(), onSubmit)}>, I get the error and nothing works as before.
enter image description here
I except to understand how handleSubmit works and how to resolve this problem.
Thanks in advance, guys!
my code:
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { Link, useNavigate } from 'react-router-dom';
import Confirmation from './Confirmation';
import * as yup from 'yup';
import { yupResolver } from '#hookform/resolvers/yup';
const schema = yup.object().shape({
name: yup.string().required(),
age: yup.number().positive().required(),
salary: yup.number().positive().required(),
email: yup.string().required(),
})
.required();
export default function LogIn() {
const { register, handleSubmit, formState: { errors }, } = useForm({
resolver: yupResolver(schema),
});
// for redirection
let navigate = useNavigate();
// modal for ghost mode
const [show, setShow] = useState(false);
const [details, setDetails] = useState({
name: '',
age: 0,
salary: 0,
email: ''
})
const sendData = async (event) => {
event.preventDefault()
const {name, age, salary, email} = details;
const res = await fetch("i hide the link :D",
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name, age, salary, email
})
})
navigate("/main");
}
const onSubmit = (data) => {
console.log(data)
}
return (
<div>
{show && <Confirmation show={show} setShow={setShow} />}
<div className="form-center">
<h1>Few Information</h1>
<form onSubmit={handleSubmit(sendData(), onSubmit)}>
<div className="form-controll">
<input type="text" {...register('name')} placeholder="Name"
onChange={(e) => setDetails({...details,name:e.target.value})}/>
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age')} placeholder="Age"
onChange={(e) => setDetails({...details,age:e.target.value})}/>
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="number" {...register('salary')} placeholder="Salary in $"
onChange={(e) => setDetails({...details,salary:e.target.value})}/>
{errors.salary?.message && <p>{errors.salary?.message}</p>}
<input type="email" {...register('email')} placeholder="Email"
onChange={(e) => setDetails({...details,email:e.target.value})}/>
{errors.email?.message && <p>{errors.email?.message}</p>}
</div>
<div className="forgot">
Don't want to share data?<br></br>
<button onClick={() => {setShow(true)}}>Ghost mode</button>
</div>
<div className="btn">
<input type='submit' value='Go' />
</div>
</form>
</div>
</div>
)
}
handleSubmit function is a wrapper for react-hook-form to manage your data inputs, validation, errors, etc.. before calling your own sendData function.
Consider doing:
export default function LogIn() {
const sendData = async (data) => {
const {name} = data;
// your post request
}
return (
<form onSubmit={handleSubmit(sendData}> // remove the useless onSubmit
<input
type="text"
{...register('name')}
placeholder="Name"
// remove the onChange prop
/>
</form>
)
}

How can I submit to custom credentials?

Hello I have the following next auth configuration:
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
export default NextAuth({
providers: [
CredentialsProvider({
name:'Login',
credentials: {
email: { label: "Email", type: "text" },
password: { label: "Password", type: "password" }
},
async authorize(credentials){
try{
const response = await fetch(`http://localhost:5001/auth/login`,{
method: "POST",
body: JSON.stringify(credentials),
headers: {'Content-type': 'application/json'}
})
const token = (await response).json()
if (response.ok && token) {
return token
}
} catch (error) {
console.log(error)
}
return null
}
})
],
})
and I have the following page:
import { getProviders, signIn } from "next-auth/react"
export default function Singin({ providers:{credentials} }) {
return (
<form method="post" action={credentials.callbackUrl}>
<label>
Email address
<input type="email" id="email" name="email" />
</label>
<label>
Password
<input type="password" id="password" name="password" />
</label>
<button type="submit">Sign in with Email</button>
</form>
)
}
export async function getServerSideProps(context) {
const providers = await getProviders()
return {
props: { providers },
}
}
I used credentials.callbackUrl in order to send the form data to the credentials but doesn't work and next-auth redirects to that page instead of make the auth.
How can I set this page?
Thanks
Try to call the signIn method and pass the credentials to it:
import { signIn } from 'next-auth/react';
export default function Singin() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
await signIn('creadentials', {
email,
password,
});
};
return (
<form method='post' onSubmit={handleSubmit}>
<label>
Email address
<input
type='email'
id='email'
name='email'
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<label>
Password
<input
type='password'
id='password'
name='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<button type='submit'>Sign in with Email</button>
</form>
);
}

React js update form value using useState

I have a React functional component, a form accepting information for events. I need to send the filled in form info using a POST request. My formData state is not updating, I have tried different onChange functions to try and get this to work. Any ideas where I am going wrong?
`
import styled from 'styled-components';
import axios from 'axios';
import Input from './Input';
import react, {useState, useEffect} from "react";
import DateTimePicker from 'react-datetime-picker';
import TimePicker from "react-time-picker";
import DatePicker from "react-date-picker";
const url = 'http://localhost:5000/events/create'
const EventForm = (props)=> {
const [dateValue, onChangeDate] = useState(new Date());
const [timeValue, onChangeTime] = useState();
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
contactEmail: '',
eventTitle: '',
eventDescription: '',
})
function onChange (e) {
let name = e.target.name ;
let value = e.target.value;
let formObj = { ...formData };
setFormData({ ...formData, [name]: value });
console.log(formData)
}
const body = {
firstName: formData.firstName,
lastName: formData.lastName,
contactEmail: formData.contactEmail,
eventTitle: formData.eventTitle,
eventDescription: formData.eventDescription,
eventDate: dateValue,
eventTime: timeValue,
}
const postFormData = async (e) => {
console.log(formData)
e.preventDefault()
await axios({
method: 'post',
url: url,
data: body,
})
.then((response) => {
console.log(response)
})
.catch(error => console.log(`Error: ${error}`));
}
// const postFormData = async (e) => {
// e.preventDefault()
// let newEvent = await fetch("http://localhost:5000/events/create",
// {
// method: "POST",
// headers: {
// 'Content-Type': 'application/json',
// 'Accept': 'application/json'
// },
// body: JSON.stringify(body)
// });
// newEvent = await newEvent.json();
// console.log(newEvent);
// }
useEffect(() => {
return () => {
console.log(formData.firstName)
}
})
return (
<form onSubmit={props.onSubmit}>
<>
{/* <DateTimePicker onChange={onChange} value={value} minDate={new Date()}/> */}
<StyledForm onSubmit={postFormData}>
<label>
First Name
</label>
<Input
name={"firstName"}
placeholder={"First Name"}
type={"text"}
value={formData.firstName}
onChange={(e) => setFormData({ ...formData, firstName: e.target.value})}
/>
<label>
Last Name
</label>
<Input
name={"lastName"}
placeholder={"Last Name"}
type={"text"}
onChange={onChange}
/>
<label>
Contact Email
</label>
<Input
name={"contactEmail"}
placeholder={"Email"}
type={"email"}
onChange={onChange}
/>
<label>
Event Date
</label>
<DatePicker onChange={onChangeDate} value={dateValue}/>
<label>
Event Time
</label>
<TimePicker onChange={onChangeTime} value={timeValue} />
<label>
Event Description
</label>
<Input
name={"eventTitle"}
placeholder={"Event Title"}
type={"text"}
onChange={onChange}
/>
<label>
Event Description
</label>
<Input
name={"eventDescription"}
placeholder={"Event Description"}
type={"text"}
width={"300px"}
height={"300px"}
onChange={onChange}
/>
<Input
name={"submit"}
type={"submit"}
value={"Create"}
/>
</form>
</>
);
}
export default EventForm;`
The formData state variable will not update immediately, your console.log will always print the original value before the update. Also when the next state is computed using the previous state like in your example, you should use the functional update version of setState:
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
contactEmail: '',
eventTitle: '',
eventDescription: '',
})
function onChange (e) {
let name = e.target.name;
let value = e.target.value;
setFormData((currentFormData) => {
const nextFormData = {
...currentFormData,
[name]: value,
})
console.log(nextFormData)
return nextFormData;
);
}

Form is not updating when using hooks

When using React Hooks my inputs are not updating. It means that when I'm updating the input in HTML, the formData is like:
{username: "", password: "", "": "a", undefined: undefined}. What's happening?
export default function Login() {
const [formData, setFormData] = useState({
username: "",
password: "",
});
async function handleSubmit(event: FormEvent) {
event.preventDefault();
const body = {
username: (event.currentTarget as any).username.value,
password: (event.currentTarget as any).password.value,
};
const res = await fetch("/api/login", {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
});
if (res.ok) {
Router.push("/");
}
}
function handleChange(event: FormEvent<HTMLInputElement>) {
setFormData((prevState) => ({
...prevState,
[event.currentTarget?.name]: event.currentTarget?.value,
}));
}
return (
<Layout>
<form onSubmit={handleSubmit}>
<FormInput
label="User name"
placeholder="Enter your username"
type="text"
value={formData.username}
onChange={handleChange}
/>
<FormInput
label="Password"
placeholder="Enter your password"
type="password"
value={formData.password}
onChange={handleChange}
/>
<input type="submit" value="Send" />
<Link href="/register">Create account</Link>
</form>
</Layout>
);
}
FormInput component is just:
type Props = {
label: string;
} & React.HTMLProps<HTMLInputElement>;
export default function FormInput({ label, ...props }: Props) {
return (
<>
<label htmlFor={label}>{label}</label>
<input {...props} />
</>
);
}
You need to implement handleChange as a callback and add the name prop. Use event.target;
export default function Login() {
const [formData, setFormData] = useState({
username: "",
password: "",
});
const handleSubmit = (event: FormEvent) => {
event.preventDefault();
const body = {
username: (event.currentTarget as any).username.value,
password: (event.currentTarget as any).password.value,
};
const res = await fetch("/api/login", {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
});
if (res.ok) {
Router.push("/");
}
}
const handleChange(event: FormEvent<HTMLInputElement>) => {
setFormData((prevState) => ({
...prevState,
[event.target?.name]: event.target?.value,
}));
}
return (
<Layout>
<form onSubmit={handleSubmit}>
<FormInput
label="User name"
placeholder="Enter your username"
type="text"
value={formData.username}
onChange={handleChange}
name="username"
/>
<FormInput
label="Password"
placeholder="Enter your password"
type="password"
value={formData.password}
onChange={handleChange}
name="password"
/>
<input type="submit" value="Send" />
<Link href="/register">Create account</Link>
</form>
</Layout>
);
}

How to change Input fields values in React?

I am not being able to change input fields.Any suggestion?
const MiddlePanel = ({ user }) => {
const history = useHistory();
const [data, setData] = useState({
firstname: '',
lastname: '',
email: '',
phoneNo: '',
});
const { firstname, lastname, email, phoneNo } = data;
useEffect(() => {
const fetchUser = async () => {
const res = await axios.get(`http://localhost:5000/users/${user._id}`);
setData({
firstname: res.data.firstname,
lastname: res.data.lastname,
email: res.data.email,
password: res.data.password,
});
};
fetchUser();
}, [user._id]);
const handleChange = (e) => {
setData({ ...data, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
const newUser = { firstname, lastname, email, phoneNo };
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify(newUser);
await axios.patch(
`http://localhost:5000/users/${user._id}`,
body,
config
);
history.push("/");
} catch (err) {}
};
return (
<div>
<Form onSubmit={handleSubmit}>
<Input
type="text"
name="firstname"
onChange={handleChange}
value={user.firstname}
/>
<Input
type="text"
name="lastname"
onChange={handleChange}
value={user.lastname}
/>
<Input
type="email"
name="email"
onChange={handleChange}
value={user.email}
/>
<Input
type="tel"
name="phoneNo"
onChange={handleChange}
value={user.phoneNo}
/>
<PrimaryButton className="btn btn-primary" style={{ width: "100%" }}>
Update
</PrimaryButton>
</Form>
</div>
);
};
I think you should use data.firstname instead of user for the value property
<div>
<Form onSubmit={handleSubmit}>
<Input
type="text"
name="firstname"
onChange={handleChange}
value={data.firstname}
/>
<Input
type="text"
name="lastname"
onChange={handleChange}
value={data.lastname}
/>
<Input
type="email"
name="email"
onChange={handleChange}
value={data.email}
/>
<Input
type="tel"
name="phoneNo"
onChange={handleChange}
value={data.phoneNo}
/>
<PrimaryButton className="btn btn-primary" style={{ width: "100%" }}>
Update
</PrimaryButton>
</Form>
</div>

Resources