React useState delays update after user initial input - javascript

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

Related

React loader spinner is not showing on Route

When a user registers it should show the spinner and send them to the dashboard page. I have it set to 8 seconds to allow plenty of time for backend but it still doesn't show. Below is the code.I have state set and using a useeffect setting a timeout and a ternary operator to navigate to the dashboard in the jsx
const CREATE_USER = gql`
mutation CreateUser($userInput: UserInput!, $profileInput: ProfileInput) {
createUser(userInput: $userInput, profileInput: $profileInput) {
token
userId
tokenExpiration
}
}
`;
const Register = (props) => {
let navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(false);
setTimeout(() => {}, 8000);
},[]);
//dont need context yet
const context = useContext(AuthContext);
const [errors, setErrors] = useState([]);
function loginUserCallback() {
login();
}
//1. record values from input here
//2. send it in empty, and hook returns with k/v pairs
const { onChange, onSubmit, values } = useForm(loginUserCallback, {
email: "",
password: "",
firstName: "",
lastName: "",
dob: "",
city: "",
state: "",
bio: "",
occupation: "",
});
//3. separate values
//replace with values.email... etc
const userInput = {
email: values.email,
password: values.password,
firstName: values.firstName,
lastName: values.lastName,
dob: values.dob,
city: values.city,
state: values.state,
};
const profileInput = {
bio: values.bio,
occupation: values.occupation,
};
const [login, { loading }] = useMutation(CREATE_USER, {
update(proxy, { data: { createUser: userData } }) {
context.login(userData);
navigate("/dashboard");
},
onError({ graphQLErrors }) {
setErrors(graphQLErrors);
},
//4. send as variables to backend
variables: {
userInput: userInput,
profileInput: profileInput,
},
});
if (loading) {
<h1>error loading</h1>;
}
return (
<>
{isLoading ? <Loading /> : <Dashboard />}
<img
src="https://floatui.com/logo.svg"
width={150}
className="mx-auto"
alt="logo"
/>
<div className="text-center font-semibold font-serif mt-4">REGISTER</div>
<form onSubmit={onSubmit}>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="email" className="block py-2 text-gray-500">
Email
</label>
<input
name="email"
type="text"
placeholder="email"
id="email"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
required
onChange={onChange}
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="password" className="block py-2 text-gray-500">
Password
</label>
<input
name="password"
type="text"
placeholder="password"
id="password"
className="w-full mt-2 px-3 py-2 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="firstName" className="block py-2 text-gray-500">
First Name
</label>
<input
name="firstName"
type="text"
placeholder="firstName"
id="firstName"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="lastName" className="block py-2 text-gray-500">
lastName
</label>
<input
type="text"
name="lastName"
placeholder="lastName"
id="lastName"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="Date of Birth" className="block py-2 text-gray-500">
Date of Birth
</label>
<input
name="dob"
type="date"
placeholder="dob"
id="dob"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="city" className="block py-2 text-gray-500">
City
</label>
<input
name="city"
type="text"
placeholder="city"
id="city"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="state" className="block py-2 text-gray-500">
State
</label>
<input
name="state"
type="text"
placeholder="state"
id="state"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="occupation" className="block py-2 text-gray-500">
Occupation
</label>
<input
name="occupation"
type="text"
placeholder="occupation"
id="occupation"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="state" className="block py-2 text-gray-500">
Bio
</label>
<textarea
name="bio"
type="text"
placeholder="bio"
id="state"
rows="4"
col="50"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="flex justify-center">
<button className="mt-5 px-6 py-2 text-white duration-150 bg-indigo-600 rounded-lg hover:bg-indigo-700 active:shadow-lg">
REGISTER
</button>
</div>
</form>
</>
);
};
export default Register;
The reason why the spinner is not showing up is because the loadingvariable from usemutation is not correctly handled.
In the code, the loading variable is destructured from the useMutation hook as follows:
const [login, { loading }] = useMutation(CREATE_USER, {...})
However, when you check if loadingistrue in the return statement, you do not return any component or text. Instead, you just have a comment. Therefore, even though the loading variable may be true, no spinner is actually displayed.
To fix this, you should return a loading spinner, such as:
if (loading) {
return <Loading />;
}
This will cause the Loading component to be displayed while the mutation is being processed.
Additionally, in the useEffect hook, you are not actually doing anything after the 8-second timeout. To display the spinner for 8 seconds, you should update the useEffect hook as follows:
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 8000);
}, []);
This will change the value of isLoading to false after 8 seconds, causing the Dashboard component to be displayed.
Overall, your Register component should look something like this:
const Register = (props) => {
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
const context = useContext(AuthContext);
const [errors, setErrors] = useState([]);
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 8000);
}, []);
const { onChange, onSubmit, values } = useForm(loginUserCallback, {
email: "",
password: "",
firstName: "",
lastName: "",
dob: "",
city: "",
state: "",
bio: "",
occupation: "",
});
const userInput = {
email: values.email,
password: values.password,
firstName: values.firstName,
lastName: values.lastName,
dob: values.dob,
city: values.city,
state: values.state,
};
const profileInput = {
bio: values.bio,
occupation: values.occupation,
};
const [login, { loading }] = useMutation(CREATE_USER, {
update(proxy, { data: { createUser: userData } }) {
context.login(userData);
navigate("/dashboard");
},
onError({ graphQLErrors }) {
setErrors(graphQLErrors);
},
variables: {
userInput: userInput,
profileInput: profileInput,
},
});
if (loading) {
return <Loading />;
}
return (
<>
{isLoading ? <Loading /> : <Dashboard />}
<img
src="https://floatui.com/logo.svg"
width={150}
className="mx-auto"
alt="logo"
/>
<div className="text-center font-semibold font-serif mt-4">REGISTER</div>
<form onSubmit={onSubmit}>
...
</form>
</>
);
};

Storing props from parent function in a const variable

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 ?? '',

Next.js: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined

I'm new to Next.js and I have encountered an error as below:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `Formik`.
my Login component
export const Login = () => {
const { LoginUser, isFetching, loginError } = useContext(UserContext)
console.log(loginError)
return (
<>
<Formik
validationSchema={LoginValidationSchema}
initialValues={{
email: "",
password: "",
}}
onSubmit={(values) => {
LoginUser(values);
console.log(values)
}}
>
{() => (
<>
<div className='w-full relative h-screen max-h-screen'>
<div className='absolute py-2'>
<Link href="/" className="text-3xl font-bold py-2">title</Link>
</div>
<Form className='w-full h-full flex flex-col justify-center items-center'>
<div className='flex flex-col bg-gray-200 mx-1 xsm:px-10 px-5 py-5 w-auto xsm:w-[350px] rounded'>
<div className='border-b-[2px] border-gray-400 py-2'>
<h1 className='font-semibold text-3xl'>Welcome back</h1>
<h1 className='font-light text-xl'>Login</h1>
</div>
<div className='flex flex-col'>
<div className='flex mt-2 flex-col'>
<label className='font-semibold' htmlFor="email">Email</label>
<Field type="email" className="px-3 outline-none focus:ring-2 ring-offset-2 ring-offset-gray-200 ring-btnColor font-semibold rounded py-2 bg-white" name="email" id="email" placeholder="Email" />
<ErrorMessage component="p" className='text-red-600 font-semibold' name="email" />
</div>
<div className='flex mt-2 flex-col'>
<label className='font-semibold' htmlFor="password">Password</label>
<Field type="password" className="px-3 outline-none focus:ring-2 ring-offset-2 ring-offset-gray-200 ring-btnColor font-semibold rounded py-2 bg-white" name="password" id="password" placeholder="Password" />
<ErrorMessage component="p" className='text-red-600 font-semibold' name="password" />
</div>
<Link href="/login/forgot_password" className='px-1 py-2 font-medium hover:underline hover:text-btnColor w-fit' >Forgot password</Link>
<button type='submit' disabled={isFetching} className="font-semibold select-none mt-4 text-white rounded px-2 py-2 bg-btnColor disabled:opacity-40 disabled:cursor-not-allowed">{isFetching ? "Submitting" : "Submit"}</button>
</div>
<p className='font-semibold mt-3'>If you don't have an account <Link href="auth/signup" className='text-btnColor hover:text-indigo-500'>signup</Link></p>
</div>
</Form>
</div>
</>
)}
</Formik>
</>
)
}
I don't understand what the error message is implying, I am exporting the login component by default, and I have no other exports, when I remove the formik component and use the normal form and input's the last part of the error becomes Check the render method of `Login` instead of Check the render method of `Formik`

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>
</>
);
};

Categories

Resources