Storing props from parent function in a const variable - javascript

I am wanting to use a Formik form to edit data records that exist in a MySQL database. The overall architecture I was planning was that a component would extract the data from the MySQL database and pass this data as array props to a child component which contains the Formik form. I was then aiming to deconstruct those props to populate a const variable called initialvalues, which Formik uses to pre-populate the fields in the form.
I have retrieved the data I want to display in the form as an array using MembersByID.jsx below:
MembersByID.jsx
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import MembersEdit from '../Members/MembersEdit'
function MembersByID(props) {
const [memberData, setMemberData] = useState([])
// console.log(memberData)
useEffect(() => {
axios.get( `http://localhost:3001/members/byId/${props.id}`)
.then((response) => {
setMemberData(response.data);
})
}, [props.id])
return (
//next line takes props from DataTable.jsx - where the prop = id, which in turn equals the row id clicked in the table
<>
<div>Member ID No from MembersByID.jsx = {props.id}</div>
<div></div>
<MembersEdit memberData={memberData}/></>
)
}
export default MembersByID
That component passes the member data as a prop called memberData to a child component called MembersEdit.jsx:
MembersEdit.jsx
import React, { useState } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup'; //yup does form validation
import axios from 'axios';
import { useMutation } from '#tanstack/react-query';
import { PatternFormat } from 'react-number-format';
//react-query useMutation code
const useMembersCreateMutation = () => {
return useMutation((formPayload) => {
return axios.post('http://localhost:3001/members', formPayload);
});
};
//Variable to store Tailwind css for 'Field' elements of Formik function
const formikField =
'my-px block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border border-gray-400 appearance-none focus:outline-none focus:ring-0 focus:border-blue-600 peer';
//Variable to store Tailwind css for 'Label' elements of Formik function
const formikLabel =
'absolute text-base text-gray-500 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-6 peer-focus:top-1 peer-focus:scale-75 peer-focus:-translate-y-4 left-1';
//Function for date fields formatting, using react-number-format
function DateField({ field }) {
return (
<PatternFormat
{...field}
format="####/##/##"
mask={['Y', 'Y', 'Y', 'Y', 'M', 'M', 'D', 'D']}
className={formikField}
placeholder="YYYY/MM/DD"
/>
);
}
//Main function - creates Formik form
function MembersEdit(props) {
const { mutate } = useMembersCreateMutation();
console.log(props)
// //Formik initial values
const initialValues = {
forename: {props?.memberData?.forename},
surname: '',
date_of_birth: '',
email_address: '',
mobile_phone: '',
address_1: '',
address_2: '',
address_3: '',
address_4: '',
address_5: '',
postcode: '',
doctor_name: '',
medical_equipment: '',
medical_conditions: '',
next_of_kin_name: '',
next_of_kin_relationship: '',
next_of_kin_phone: '',
next_of_kin_local: '0',
key_safe_code: '',
directions: '',
deceased_date: '',
normally_escorted: '',
blue_badge_holder: '0',
};
// Yup field validation
const validationSchema = Yup.object().shape({
forename: Yup.string()
.required('*Forename is required')
.max(35, 'Forename can be a maximum of 35 characters'),
surname: Yup.string()
.required('*Surname is required')
.max(35, 'Surname can be a maximum of 35 characters'),
date_of_birth: Yup.string().required('*Date of Birth is required'),
email_address: Yup.string()
.email('*Invalid email address format')
.max(255, 'Email address can be a maximum of 255 characters'),
mobile_phone: Yup.string().max(
12,
'Mobile phone can be a maximum of 12 characters'
),
address_1: Yup.string()
.required('*Address Line 1 is required')
.max(35, 'Address Line 1 can be a maximum of 35 characters'),
address_2: Yup.string().max(
35,
'Address Line 2 can be a maximum of 35 characters'
),
address_3: Yup.string().max(
35,
'Address Line 3 can be a maximum of 35 characters'
),
address_4: Yup.string().max(
35,
'Address Line 4 can be a maximum of 35 characters'
),
address_5: Yup.string().max(
35,
'Address Line 5 can be a maximum of 35 characters'
),
postcode: Yup.string()
.required('*Postcode is required')
.max(12, 'Postcode can be a maximum of 12 characters'),
doctor_name: Yup.string().max(
35,
'Doctor can be a maximum of 35 characters'
),
medical_equipment: Yup.string().max(
255,
'Medical Equipment can be a maximum of 255 characters'
),
initial_medical_conditions: Yup.string(),
next_of_kin_name: Yup.string().max(
70,
'Next of Kin Name can be a maximum of 70 characters'
),
next_of_kin_relationship: Yup.string().max(
40,
'Next of Kin Relationship can be a maximum of 40 characters'
),
next_of_kin_phone: Yup.string().max(
12,
'Next of Kin Phonecan be a maximum of 12 characters'
),
key_safe_code: Yup.string().max(
8,
'Key Safe Code can be a maximum of 8 characters'
),
deceased: Yup.string(),
});
// State used to display success/error posting message
const [createMsg, setCreateMsg] = useState('');
return (
<>
{/* in the below, the two question marks mean it only attempts to get the prop value if it is not null */}
{props?.memberData?.forename}
<div className="createMemberPage px-5">
<Formik
enableReinitialize={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(values, formik) => {
mutate(values, {
onSuccess: () => {
setCreateMsg('New Member Created!');
formik.resetForm();
},
onError: (response) => {
setCreateMsg('Error: Member not created - Keep Calm and Call Jonathan');
console.log(response);
},
});
} }
>
<Form className="formContainer">
<h1 className="pb-3 text-xl font-semibold">General Information</h1>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="forename"
placeholder=" " />
<label className={formikLabel}>Forename</label>
<ErrorMessage
name="forename"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="surname"
placeholder=" " />
<label className={formikLabel}>Surname</label>
<ErrorMessage
name="surname"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="date_of_birth"
placeholder=" "
component={DateField} />
<label className={formikLabel}>Date Of Birth</label>
<ErrorMessage
name="date_of_birth"
component="span"
className="text-red-600" />
</div>
<h1 className="pb-3 pt-5 text-xl font-semibold">
Contact Information
</h1>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="email_address"
placeholder=" " />
<label className={formikLabel}>Email Address</label>
<ErrorMessage
name="email_address"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="mobile_phone"
placeholder=" " />
<label className={formikLabel}>Mobile Phone</label>
<ErrorMessage
name="mobile_phone"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="address_1"
placeholder=" " />
<label className={formikLabel}>Address Line 1</label>
<ErrorMessage
name="address_1"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="address_2"
placeholder=" " />
<label className={formikLabel}>Address Line 2</label>
<ErrorMessage
name="address_2"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="address_3"
placeholder=" " />
<label className={formikLabel}>Address Line 3</label>
<ErrorMessage
name="address_3"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="address_4"
placeholder=" " />
<label className={formikLabel}>Address Line 4</label>
<ErrorMessage
name="address_4"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="address_5"
placeholder=" " />
<label className={formikLabel}>Address Line 5</label>
<ErrorMessage
name="address_5"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="postcode"
placeholder=" " />
<label className={formikLabel}>Postcode</label>
<ErrorMessage
name="postcode"
component="span"
className="text-red-600" />
</div>
<h1 className="pb-3 pt-5 text-xl font-semibold">
Medical Information
</h1>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="doctor_name"
placeholder=" " />
<label className={formikLabel}>Doctor Name</label>
<ErrorMessage
name="doctor_name"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="medical_equipment"
placeholder=" " />
<label className={formikLabel}>Medical Equipment</label>
<ErrorMessage
name="Medical Equipment"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="initial_medical_conditions"
placeholder=" " />
<label className={formikLabel}>Medical Conditions</label>
<ErrorMessage
name="initial_medical_conditions"
component="span"
className="text-red-600" />
</div>
<h1 className="pb-3 pt-5 text-xl font-semibold">Next Of Kin</h1>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="next_of_kin_name"
placeholder=" " />
<label className={formikLabel}>Next of Kin Name</label>
<ErrorMessage
name="next_of_kin_name"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="next_of_kin_relationship"
placeholder=" " />
<label className={formikLabel}>Next of Kin Relationship</label>
<ErrorMessage
name="next_of_kin_relationship"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="next_of_kin_phone"
placeholder=" " />
<label className={formikLabel}>Next of Kin Phone</label>
<ErrorMessage
name="next_of_kin_phone"
component="span"
className="text-red-600" />
</div>
<div className="pb-2">
<label className="text-gray-500 px-2.5">Next Of Kin Local</label>
<ErrorMessage
name="next_of_kin_local"
component="span"
className="text-red-600" />
<Field
type="checkbox"
value="1"
className="border border-gray-400 rounded-lg outline-0 text-gray-500"
autoComplete="off"
id="inputCreateMember"
name="next_of_kin_local"
placeholder=" " />
</div>
<h1 className="pb-3 pt-5 text-xl font-semibold">Other Information</h1>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="key_safe_code"
placeholder=" " />
<label className={formikLabel}>Key Safe Code</label>
<ErrorMessage
name="key_safe_code"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="directions"
placeholder=" " />
<label className={formikLabel}>Directions to Home</label>
<ErrorMessage
name="directions"
component="span"
className="text-red-600" />
</div>
<div className="pb-2 relative">
<Field
className={formikField}
autoComplete="off"
id="inputCreateMember"
name="deceased"
placeholder=" "
component={DateField} />
<label className={formikLabel}>Deceased Date</label>
<ErrorMessage
name="deceased"
component="span"
className="text-red-600" />
</div>
<div className="pb-2">
<label className="text-gray-500 px-2.5">Normally Escorted</label>
<ErrorMessage
name="normally_escorted"
component="span"
className="text-red-600" />
<Field
type="checkbox"
value="1"
className="border border-gray-400 rounded-lg outline-0 text-gray-500"
autoComplete="off"
id="inputCreateMember"
name="normally_escorted"
placeholder=" " />
</div>
<div className="pb-2">
<label className="text-gray-500 px-2.5">Blue Badge Holder</label>
<ErrorMessage
name="blue_badge_holder"
component="span"
className="text-red-600" />
<Field
type="checkbox"
value="1"
className="border border-gray-400 rounded-lg outline-0 text-gray-500"
autoComplete="off"
id="inputCreateMember"
name="blue_badge_holder"
placeholder=" " />
</div>
<div className="flex flex-col items-center">
<button
className="text-base text-white bg-blue-500 border hover:bg-blue-600 hover:text-gray-100 p-2 px-20 rounded-lg mt-5"
type="submit"
>
Create Member
</button>
</div>
<br></br>
<h1 className={(createMsg === "") ? "" :
((createMsg === "New Member Created!") ? "text-xl text-blue-600 font-bold p-2 border border-blue-600 text-center" : "text-xl text-red-600 font-bold p-2 border border-red-600 text-center")}> {/* This code only formats the class, hence shows the border, when a message is being displayed */}
{createMsg}
</h1>
</Form>
</Formik>
</div></>
);
}
export default MembersEdit;
The props data arriving in MembersEdit is as follows, when logged in console.log:
Props Data from console.log
As a test, I rendered one part of that props array in the return section of the MembersEdit function, using the line {props?.memberData?.forename}. This renders on the screen OK.
Next, I tried adding the same line of code in the forename part of the initialValues const array, so in the part:
const initialValues = {
forename: {props?.memberData?.forename},
But I then get a parsing error stating that a comma is expected:
Parsing Error
I'm not sure why the line of code: {props?.memberData?.forename} works when rendering the forename in the return section of the MemberEdit component, but not in the const array section. Am I just making a simple syntax error of some description, or is my entire approach here incorrect?

What you have here
props?.memberData?.forename
is a plain value - probably either a string or undefined.
When in the context of JSX, putting {} brackets around something indicates to interpret what's inside as a value to interpolate into the HTML. So doing
return (
<>
{props?.memberData?.forename}
works.
But that's only in the context of JSX. When outside of JSX, { indicates either the start of a block, or the start of an object literal. When in an expression context, it indicates the start of an object literal. Here, you're in an expression context:
const initialValues = {
forename: // expression goes here
You don't need to interpolate anything, or create a nested object - you just need the plain value from props.
const initialValues = {
forename: props?.memberData?.forename,
Doing
const initialValues = {
forename: {props?.memberData?.forename},
fails because the { above indicates the start of an object literal, but objects require key-value pairs, and props?.memberData?.forename is only a value (an expression). For it to be valid syntax, it would need a key as well, such as { someKey: props?.memberData?.forename }.
Another issue to consider is that optional chaining evaluates to undefined when the chain fails. You might want to account for that so that forename is set to the empty string if the chain fails, instead of undefined.
const initialValues = {
forename: props?.memberData?.forename ?? '',

Related

Html Form is not taking input on using handlechange event as use state hook

I have created a register page and tried to access the input value using handleChange event but the form is not taking any input. If the 'value=""' field of form elements is commented or their values are set null then the form is working. I tried by declaring a global
const {name, email, phone, work, password, cpassword} = user;
and passed the attributes to their respective value="" field but still not worked. How to solve this issue?
This is the code of my signup page.
import React ,{useState} from "react";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap";
import "../css/Signup.css"
import img from "../imgs/register.png"
import { NavLink } from "react-router-dom";
const Signup = ()=>{
const [user, setUser] = useState({
name:"", email:"", phone:"", work:"", password:"", cpassword:""
});
let name, value;
const handleChange = (event)=>{
name = event.target.name;
value = event.target.value;
setUser({...user, [name]:value});
}
const postData = (event)=>{
}
return (
<section className="section-container">
<div className="container">
<div className="myCard">
<div className="row">
<div className="col-md-6">
<div className="myLeftCtn">
<form className="myForm text-center" method="POST">
<header>Sign Up</header>
<div className="form-group">
<i className="fas fa-user"></i>
<input className="myInput" type={"text"}
value={user.name}
onChange={handleChange}
placeholder="Username" id="username" required></input>
</div>
<div className="form-group">
<i className="fas fa-envelope"></i>
<input className="myInput" type={"text"}
value={user.email}
onChange={handleChange}
placeholder="Email" id="email" required></input>
</div>
<div className="form-group">
<i className="fas fa-phone"></i>
<input className="myInput" type={"text"}
value={user.phone}
onChange={handleChange}
placeholder="Mobile Number" id="phone" required></input>
</div>
<div className="form-group">
<i className="fas fa-user-tie"></i>
<input className="myInput" type={"text"}
value={user.work}
onChange={handleChange}
placeholder="Profession" id="work" required></input>
</div>
<div className="form-group">
<i className="fas fa-lock"></i>
<input className="myInput" type={"password"}
value={user.password}
onChange={handleChange}
placeholder="Password" id="password" required></input>
</div>
<div className="form-group">
<i className="fas fa-lock"></i>
<input className="myInput" type={"password"}
value={user.cpassword}
onChange={handleChange}
placeholder="Confirm Password" id="cpassword" required></input>
</div>
<div className="form-group">
<label>
<input id="check_1" name="check_1" type={"checkbox"} required />
<small>I read and agree to Terms and Conditions</small>
<div className="invalid-feedback">You must check the box.</div>
</label>
</div>
<input type={"submit"} onClick={postData} className="butt" value={"Create Account"}/>
</form>
</div>
</div>
<div className="col-md-6">
<div className="box">
<figure>
<img className="signup-img" src={img} alt="signup-img"></img>
</figure>
<div className=""><NavLink className="butt_out" to="/login">I am already registered</NavLink></div>
</div>
</div>
</div>
</div>
</div>
</section>
)
}
export default Signup;
Everything looks great.Accept this line of code
<input type="submit" onClick={postData} className="butt" value={"Create Account"}/>
Your event.target.name will always be "". You will need to add name attribute to your form like so:
<input className="myInput" type={"text"} name="name"
value={user.name}
onChange={handleChange}
placeholder="Username" id="username" required></input>
Alternatively, you can use event.target.id, but you will need to update your form so it matches the user object. E.g. input for username should have an id of "name"
the name is doesn't passed
Example:
<input className="myInput" type={"text"} name="email" value={user.email}
onChange={handleChange} placeholder="Email" id="email" required>
</input>
and you don't need to declare let name, value;
outside the function
Function should look like :
const handleChange = (event) => {
const name = event.target.name;
const value = event.target.value;
setUser({...user, [name]:value});
}
or
const handleChange = (event) => {
setUser({...user, [event.target.name]:event.target.value});
}

REACT- Making 2 different dynamic displays depending on a selection checkboxes ( everything is on the same page now)

depending on the selection of my user Change the type or Choose the comments (he can select only one choice), there will be a different display, but my code displayed both options in the same page.
So, in the begining there are only 2 checkboxes Change the type or Choose the comments then depending on the selection the display appears
export default function App(){
...
return (
<>
{/* Step 1- 2 checkboxes are displayed */}
<form onSubmit={handleSubmit}>
<input type="checkbox" onChange={(e) => setType(e.target.value)} />
<span className="text-md p-1 font-bold leading-8 text-gray-500">
Change the type{" "}
</span>
<input type="checkbox" onChange={(e) => setComment(e.target.value)} />
<span className="text-md p-1 font-bold leading-8 text-gray-500">
Choose the comments{" "}
</span>
</form>
{/*Step 2 - if setType ==true then display */}
<form onSubmit={handleSubmit}>
<input
type="text"
value={menu}
placeholder="Menu"
onChange={(e) => setMenu(e.target.value)}
/>
<div className="text-md font-bold text-gray-500 flex flex-wrap gap-x-2 ">
Type : <CustomDropdown options={LOCATION} isMulti={false} />
</div>
<label className="mr-3 h-6 text-md font-bold leading-8 text-gray-500">
Location:
</label>
<input
type="text"
value={location}
placeholder="Location"
onChange={(e) => setLocation(e.target.value)}
/>
</form>
{/*Step 2 - if setComment ==true (selected) then display */}
<form onSubmit={handleSubmit}>
<Comments />
<input
type="text"
value={menu}
placeholder="Menu"
onChange={(e) => setMenu(e.target.value)}
/>
<div className="text-md font-bold text-gray-500 flex flex-wrap gap-x-2 ">
Type : <CustomDropdown options={LOCATION} isMulti={false} />
</div>
<label className="mr-3 h-6 text-md font-bold leading-8 text-gray-500">
Location:
</label>
<input
type="text"
value={location}
placeholder="Location"
onChange={(e) => setLocation(e.target.value)}
/>
</form>
</>
);
}
Here is my code
Here a picture to get the idea :
I understood better thanks to the picture you added, here is the code: https://codesandbox.io/s/first-page-with-dynamic-field-forked-vpxyhu?file=/src/App.js

Radio button validation not disappear when select a button using Formik and Yup

I am working to handle a signup form with next js, I used Formik from form and Yup for validation, all things are working correctly except radio buttons. The errors appear correctly, but when I select a radio button, the error does not disappear. I couldn't find any solution for solving this issue.
This is my form code:
<Formik
initialValues={{
email: "",
password: "",
confirmPassword: "",
accountType: "",
accountDescribe: "",
}}
validationSchema={validate}
onSubmit={values => console.log("register", values)}
>
{formik => (
<div>
<Form className="space-y-6">
<div>
<label
for="email"
className="block text-sm font-medium text-gray-700"
>
{" "}
Email address{" "}
</label>
<div className="mt-1">
<TextField id="email" name="email" type="email" />
</div>
</div>
<div>
<label
for="password"
className="block text-sm font-medium text-gray-700"
>
{" "}
Password{" "}
</label>
<div className="mt-1">
<TextField
id="password"
name="password"
type="password"
/>
</div>
</div>
<div>
<label
for="confirmPassword"
className="block text-sm font-medium text-gray-700"
>
{" "}
Confirm password{" "}
</label>
<div className="mt-1">
<TextField
id="confirmPassword"
name="confirmPassword"
type="password"
/>
</div>
</div>
<div class="mt-4">
<span class="text-gray-700">
How did you hear about us?
</span>
<div class="mt-2">
<Radio
type="radio"
name="accountType"
value="google"
label="Google"
/>
<Radio
type="radio"
name="accountType"
value="facebook"
label="Facebook"
/>
<Radio
type="radio"
name="accountType"
value="instagram"
label="Instagram"
/>
<Radio
type="radio"
name="accountType"
value="person/business"
label="Person/Business"
/>
<Radio
type="radio"
name="accountType"
value="other"
label="Other"
/>
</div>
<span className="text-red-600">
<ErrorMessage
name="accountType"
className="text-red-600"
/>
</span>
</div>
<div class="mt-4">
<span class="text-gray-700">What best describe you?</span>
<div class="mt-2">
<Radio
type="radio"
name="accountDescribe"
value="salon, spa or barbershop owner"
label="Salon, spa or Barbershop Owner"
/>
<Radio
type="radio"
name="accountDescribe"
value="licensed professional"
label="Licensed professional"
/>
<Radio
type="radio"
name="accountDescribe"
value="student"
label="Student"
/>
<Radio
type="radio"
name="accountDescribe"
value="school"
label="School"
/>
</div>
<span className="text-red-600">
<ErrorMessage name="accountDescribe" />
</span>
</div>
<div>
<button
type="submit"
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Register
</button>
</div>
</Form>
</div>
)}
</Formik>
This is my validation schema:
const validate = Yup.object().shape({
email: Yup.string().email("Email id invalid").required("Email is required"),
password: Yup.string()
.min(6, "Password must be at least 6 characters")
.required("Password is required"),
confirmPassword: Yup.string()
.oneOf([Yup.ref("password"), null], "Password must match")
.required("Confirm password is required"),
accountType: Yup.string().required("Select one of the above button"),
accountDescribe: Yup.string().required("Select one of the above button"),
});
And this is my radio button component:
import {useField} from "formik";
export const Radio = ({type, label, ...props}) => {
const [field, meta] = useField(props);
console.log(props);
return (
<>
<label class="inline-flex items-center mr-6">
<input type={type} name={field.name} value={field.value} />
<span class="ml-2">{label}</span>
</label>
</>
);
};
Put this code in your radio button component
import {useField} from "formik";
export const Radio = ({type, label,...props}) => {
const [field, meta] = useField(props);
return (
<>
<label className="inline-flex items-center mr-6">
<input type={type} {...field}{...props} />
<span className="ml-2">{label}</span>
</label>
</>
);
};

React useState delays update after user initial input

I understand that React's useState hook is an asynchronous method, hence why it has a callback. However, I want to make the initial user input update (state is updated after only after second input) the state when the handleChange method is triggered. How do I do that -- update react without delay?
code:
import React, { useState, createRef } from "react";
import { Link } from "react-router-dom";
import { useSelector, useDispatch } from 'react-redux';
import DocumentHead from "../DocumentHead";
import Button from "../Button";
import phoneLady from "../../assets/images/phoneLady.jpg";
import setBgImage from "../../utils/setBgImage"
export default function register() {
const pageName = "Regsiter";
const [form, setForm] = useState({
title: "",
firstName: "",
lastName: "",
emailAddress: "",
phoneNumber: "",
dateOfBirth: "",
organization: "",
password: "",
confirmPassword: "",
finalFormIsSlidedIn: false,
buttonIsDisabled: true,
termsAndConditionsIsChecked: false,
});
const handleChange = (e) => {
const target = e.target;
const name = target.name
const value = target.type === 'checkbox' ? target.checked : target.value
setForm((state) => {
return {
...state,
[name]: value
}
}, console.log(form))
}
const handleSubmit = (e) => {
e.preventDefault();
}
return (
<>
<DocumentHead title={pageName} />
<section>
<div id="orderbook-form">
<form className="h-full">
<div className="pt-20 pb-10 px-12">
<h1 id="orderbook-home" className="text-center mb-10 leading-6 md:hidden">
<Link to="/" className="text-gray-400">Orderbook Online</Link>
</h1>
<div className="px-4 sm:px-0 mb-3">
<h2 className="text-lg font-medium leading-6 pb-3 sm:pb-2">
Nice to meet you,
</h2>
<p className="mt-1 text-sm text-gray-600">
create an account to start using
Orderbook
</p>
</div>
<div className="grid grid-cols-1 gap-5">
<div
id="registration-steps"
className="col-span-12"
>
{/*Registration -- First step*/}
<div
id="first-step-fields"
className="col-span-12 grid grid-cols-1 gap-4"
>
<div className="col-span-12">
<select
id="title"
name="title"
autoComplete="title"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
value={form.value}
onChange={(e) => handleChange(e)}
>
<option defaultValue="Please choose">
Please choose
</option>
<option value="Mr">
Mr
</option>
<option value="Miss">
Miss
</option>
<option value="Mrs">
Mrs
</option>
<option value="Ms">
Ms
</option>
<option value="Dr">
Dr
</option>
<option value="Other">
Other
</option>
</select>
</div>
<div className="col-span-12 grid grid-cols-2 gap-4">
{/*Fix grid*/}
<div className="col-span-1">
<input
type="text"
name="firstName"
value={form.firstName}
id="first-name"
autoComplete="first-name"
placeholder="First name"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>
{/*fix grid*/}
<div className="col-span-1">
<input
type="text"
name="lastName"
value={form.lastName}
id="last-name"
autoComplete="last-name"
placeholder="Last name"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>
</div>
<div className="col-span-12">
<input
type="text"
name="emailAddress"
value={form.emailAddress}
id="email-address"
autoComplete="email"
placeholder="Email address"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-12 text-right">
<span
id="next-field-button"
className={`form-slide-button ${
form.finalFormIsSlidedIn
? "hidden"
: ""
}`}
onClick={() =>
slideFinalFormIn()
}
>
Next{" "}
<i
className="fa fa-long-arrow-right"
aria-hidden="true"
></i>
</span>
</div>
</div>
{/*Registration -- Final step*/}
<div
id="final-step-fields"
className="grid gap-4"
ref={finalFormStepRef}
>
<div className="col-span-12">
<input
type="tel"
name="phoneNumber"
id="phone-number"
value={form.phoneNumber}
pattern="[0-9]{4}-[0-9]{3}-[0-9]{4}"
autoComplete="phone-number"
placeholder="Phone number"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-12">
<input
type="text"
id="data-of-birth"
name="dateOfBirth"
value={form.dateOfBirth}
autoComplete="date-of-birth"
placeholder="Date of birth (MM/DD/YYYY)"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onFocus={(e) =>
(e.target.type =
"date")
}
onBlur={(e) =>
(e.target.type =
"text")
}
onChange={(e) => handleChange(e)}
/>
</div>
{/*<div className="col-span-12">
<input
type="text"
id="organization"
name="organization"
value={form.organization}
autoComplete="organization"
placeholder="Organization/Company"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>*/}
<div className="col-span-12 grid grid-cols-2 gap-4">
<div className="col-span-1">
<input
type="password"
id="password"
name="password"
value={form.password}
autoComplete="password"
placeholder="Password"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-1">
<input
type="password"
id="confirm-password"
name="confirmPassword"
value={form.confirmPassword}
autoComplete="confirm-password"
placeholder="Confirm password"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
</div>
<div className="col-span-12 text-left">
<span
id="previous-field-button"
className="form-slide-button"
onClick={() =>
slideFinalFormOut()
}
>
<i
className="fa fa-long-arrow-left"
aria-hidden="true"
></i>{" "}
Previous
</span>
</div>
</div>
</div>
<div className="col-span-12">
<div className="flex items-start">
<div className="flex items-center h-5">
<input
id="terms-and-conditions"
name="termsAndConditionsIsChecked"
type="checkbox"
className="focus:ring-white h-4 w-4 text-indigo-600 border-black rounded"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="ml-3 text-sm">
<label
htmlFor="terms-and-conditions"
className="font-medium text-black"
>
By signing up, you agree
to
</label>{" "}
<Link to="/">
Orderbook’s Terms of Use
& Privacy Policy
</Link>
</div>
</div>
</div>
<div className="col-span-12 mt-1">
<Button
type="submit"
title="Sign up"
buttonClass="register-button auth-button"
buttonDisabled={
form.buttonIsDisabled
? true
: ""
}
/>
</div>
<div
id="login-existing-account"
className="col-span-12 mt-1 account-signal"
>
<div className="text-center">
Already have an account?{" "}
<Link to="/login">Log in</Link>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
</>
);
}
I think you can not reach to top 0, you can use a form library for less render and manage all states wisely, please check hook-form

Passing a second argument through onSubmit in forms using react and EmailJs

I have a full form written out with other components for the success of the submission and validation, but now I want to connect to Emailjs so I can receive the email in my actual gmail. Heres what the EmailJs code wants me to add to my code but Im not sure how to pass 2 arguments together and make it work.
function sendEmail(e) {
e.preventDefault();
emailjs.sendForm('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', e.target, 'YOUR_USER_ID')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
}
and here is my code
import React from 'react'
import useForms from './useForms'
import validate from './validateInfo'
const FormContact = ({submitForm}) => {
const { handleChange, values, handleSubmit, errors} = useForms(submitForm, validate);
return (
<div className="form-content-right">
<form action="" className="form" onSubmit={handleSubmit}>
<h6>Get in contact with us!</h6>
<div className="form-inputs">
<label htmlFor="name" className="form-label">
Full Name:
</label>
<input id='name'
type="text"
name='name'
className="form-input"
placeholder='Name'
value={values.name}
onChange={handleChange}
/>
{errors.name && <p>{errors.name}</p>}
</div>
<div className="form-inputs">
<label htmlFor="email" className="form-label">
Email Address:
</label>
<input id='email'
type="email"
name='email'
className="form-input"
placeholder='Email'
value={values.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div className="form-inputs">
<label htmlFor="number" className="form-label">
Contact Number:
</label>
<input id='number'
type="tel"
name='number'
className="form-input"
placeholder='Contact number' />
</div>
<div className="form-inputs">
<label htmlFor="country" className="form-label">
Country:
</label>
<input id='country'
type="country"
name='country'
className="form-input"
placeholder='Country'
value={values.country}
onChange={handleChange}
/>
{errors.country && <p>{errors.country}</p>}
</div>
<div className="form-inputs">
<label htmlFor="message" className="form-label">
Message:
</label>
<textarea id='message'
type="message"
name='message'
className="form-input"
placeholder='Enter message here'
value={values.message}
onChange={handleChange}
/>
</div>
<button className="form-input-btn" type='submit' >
Contact Us
</button>
</form>
</div>
)
}
export default FormContact
I need handleSubmit for my code to work but also somehow need to add "sendEmail" to that same argument inside onSubmit
You can create an anonymous function that calls both your needed functions:
<form action="" className="form" onSubmit={(e) => {handleSubmit(e); sendEmail(e);}} >

Categories

Resources