React TS, First submit returns empty array - reactjs

I'm trying to make simple form using React,Typescript, have done some inputs and while adding them with onChange to one main state, first submit always returns empty. Why?
import React from "react";
import { useState } from "react";
import { Form } from "../components/Form/Form";
import { Navbar } from "../components/Navbar";
export const MainPage = () => {
const [formData, setFormData] = useState([]);
return (
<div className="w-full flex">
<Navbar />
<Form formData={formData} setFormData={setFormData} />
</div>
);
};
import React from "react";
import { useState } from "react";
interface Props{
formData: string[];
setFormData: React.Dispatch<React.SetStateAction<any>>;
}
export const Form: React.FC<Props> = ({setFormData, formData}) => {
const [organization, setOrganization] = useState<string>("");
const [title, setTitle] = useState<string>("");
const [firstName, setFirstName] = useState<string>("");
const [lastName, setLastName] = useState<string>("");
const [languages, setLanguages] = useState<string>("");
const [employmentType, setEmploymentType] = useState<string>("");
const [profession, setProfession] = useState<string>("");
const [proficiency, setProficiency] = useState<string>("");
const submitData = (e: any) => {
const data = {
organization,
title,
firstName,
lastName,
languages,
employmentType,
profession,
proficiency,
};
setFormData((prevData: any) => [...prevData, data]);
console.log(formData)
}
return (
<div className="w-full">
<div className="w-3/4 mx-auto mt-5">
<h1 className="text-2xl">About you</h1>
<div className="top flex mt-16 gap-8">
<div>
<h2 className="text-xl font-bold">Personal info</h2>
<p className="text-sm font-extralight">
Provide your personal info
</p>
</div>
<div className="flex flex-col gap-5">
<div>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setOrganization(e.target.value);
}}
className="w-full bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Organization"
></input>
</div>
<div className="flex gap-3">
<select
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
setTitle(e.target.value);
}}
className="bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
>
<option value="Title">Title</option>
<option value="Mr">Mr</option>
<option value="Mrs">Mrs</option>
<option value="Miss">Miss</option>
<option value="Ms">Ms</option>
</select>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setFirstName(e.target.value);
}}
className="bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="First name"
></input>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setLastName(e.target.value);
}}
className="bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Last name"
></input>
</div>
</div>
</div>
</div>
<hr className="mt-16"></hr>
<div className="bottom w-3/4 mx-auto mt-16">
<div>
<h2 className="text-xl font-bold">Professional info</h2>
<p className="text-sm font-extralight">
Provide your professional info
</p>
</div>
<div className="mt-14">
<div className="flex flex-col gap-8 items-center">
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setLanguages(e.target.value);
}}
className="w-3/4 bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Language(s) separate with comma"
></input>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setEmploymentType(e.target.value);
}}
className="w-3/4 bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Type of employment"
></input>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setProfession(e.target.value);
}}
className="w-3/4 bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Profession"
></input>
<input
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setProficiency(e.target.value);
}}
className="w-3/4 bg-gray-200 p-2 rounded-md placeholder:text-sm placeholder:text-black"
placeholder="Proficiency level"
></input>
</div>
</div>
</div>
<div className="w-3/4 flex justify-end mt-7">
<button onClick={(e) => submitData(e)} className="bg-sky-800 p-2 text-white rounded-md">Submit</button>
</div>
</div>
);
};
Read other threads about similar issue but there was mentioned using async, i believe there would be another way to fix this. Thank you

Hi there setState in Reactjs is asynchronous so when you called submitData console.log(formData) gets triggered even before the setState completed its task and with asynchronous code, javascript does not have to wait for setState to finish up it just keeps running other tasks.
setFormData((prevData: anyType) => {
const newData = [...prevData, data];
console.log(newData);
return newData;
});

Related

Black screen in react code - possible firebase auth issue

this code is giving me a blank screen i have no idea as to why i would assume its firebase auth or the logic giving me trouble im running this in vscode and its compiling sucessfully
import { createUserWithEmailAndPassword } from "firebase/auth";
import React, { useState } from "react";
import { auth } from "../firebase";
import { Link } from "react-router-dom";
const SignUp = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");
const [error, setError] = useState("");
const signUp = (e) => {
e.preventDefault();
auth.createUserWithEmailAndPassword(email, password).then((userCredential) => {
userCredential.user
.updateProfile({
displayName: name,
})
.then(() => {
console.log("user name added");
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
setError(error.message);
});
};
return (
<div className="container mx-auto flex justify-center pt-6">
<form className="bg-white p-6 rounded-lg shadow-xl" onSubmit={signUp}>
<div className="mb-4">
<label
className="block text-gray-700 font-medium mb-2"
htmlFor="name"
>
Name
</label>
<input
className="w-full border border-gray-400 p-2 rounded-md"
id="name"
type="text"
placeholder="Enter your name"
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="mb-4">
<label
className="block text-gray-700 font-medium mb-2"
htmlFor="email"
>
Email
</label>
<input
className="w-full border border-gray-400 p-2 rounded-md"
id="email"
type="email"
placeholder="Enter your email"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mb-4">
<label
className="block text-gray-700 font-medium mb-2"
htmlFor="password"
>
Password
</label>
<input
className="w-full border border-gray-400 p-2 rounded-md"
id="password"
type="password"
placeholder="Enter your password"
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="text-red-500 text-xs mb-4">{error}</div>
<button
className="bg-indigo-500 hover:bg-indigo-600 text-white py-2 px-4
rounded-md"
type="submit"
>
Sign Up
</button>
<Link
to="/login"
className="text-indigo-500 hover:text-indigo-600 font-medium py-2 px-4"
>
Already have an account?
</Link>
</form>
</div>
);
};
export default SignUp;
was trying to make a signup page for my website that took in email and password to authenticate but also took a name to display on profile

How to pass dropdown value in a form coming from a separate component

I have a form with two fields. One is a textfield and I cant get the data without any problem. The second field is a dropdown. This dropdown is a separate component within the form.
How can I pass the selected dropdown value with my form?
The setup is like this:
Form:
import { useState } from 'react';
import { SensorTypeDropdown } from '../add/SensorTypeDropdown'
const AddSensor = () => {
const [imei, setImei] = useState('');
const handleSubmit = (event: any) => {
alert('Sensor with IMEI: ' + imei + ' created.');
event.preventDefault(); //prevents page from refreshing
setImei('')//clears form input data
}
return (
<div className="container mx-auto">
<form className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit}>
<div className="mb-4">
<label className="block text-sm font-bold mb-2" htmlFor="imei">
IMEI
</label>
<input className="border rounded w-full py-2 px-3 focus:shadow-outline focus:outline-sky-700" value={imei} onChange={event => setImei(event.target.value)} id="sensorName" />
</div>
<div className="mb-6">
<label className="block text-sm font-bold mb-2" htmlFor="sensorType">
Sensor type
</label>
<SensorTypeDropdown/>
</div>
<div className="flex items-center justify-between">
<input type="submit" className="cursor-pointer bg-sky-700 hover:bg-sky-800 text-white font-bold py-2 px-4 rounded focus:shadow-outline" value="Create sensor" />
</div>
</form>
</div>
)
}
export default AddSensor;
And my separate dropdown component:
import { SharedAmbientSurrounding } from "#libs/data";
import { useState } from "react";
import { getEnumKeys } from "../../helpers/getEnumKeys";
export const SensorTypeDropdown = () => {
const [currentType, setCurrentType] = useState<SharedAmbientSurrounding>(SharedAmbientSurrounding.TEMPERATURE);
const [selectedType, setSelectedType] = useState('')
return (
<select
value={currentType}
onChange={(e) => {
setCurrentType(SharedAmbientSurrounding[e.target.value as keyof typeof SharedAmbientSurrounding]);
}}
>
{getEnumKeys(SharedAmbientSurrounding).map((key, index) => (
<option key={index} value={SharedAmbientSurrounding[key]}>
{key}
</option>
))}
</select>
);
}
Any help is appreciated. Thanks!
You should manage the dropdown state in the parent component AddSensor
AddSendor
const AddSensor = () => {
const [imei, setImei] = useState('');
const [type, setType] = useState(SharedAmbientSurrounding.TEMPERATURE);
const handleSubmit = (event) => {
alert('Sensor with IMEI: ' + imei + ' and type: ' + type + ' created.');
event.preventDefault(); //prevents page from refreshing
//clears form input data
setImei('');
setType(SharedAmbientSurrounding.TEMPERATURE);
}
....
<div className="mb-6">
<label className="block text-sm font-bold mb-2" htmlFor="sensorType">
Sensor type
</label>
<SensorTypeDropdown value={type} onChange={setType} />
</div>
...
}
SensorTypeDropdown
export const SensorTypeDropdown = ({value, onChange}) => {
return (
<select
value={value}
onChange={e => onChange(e.target.value)}
>
{getEnumKeys(SharedAmbientSurrounding).map((key, index) => (
<option key={key} value={SharedAmbientSurrounding[key]}>
{key}
</option>
))}
</select>
);
}

Passing values from a constant to the e.target.value

I am working on building out a radio component and when checked I want the values from the radio button to pass when set onBlur. I am trying to pass a function to the onBlur but I am not seeing the values on my Form Submit action.
const [isChecked, setIsChecked] = React.useState<boolean>(defaultValue);
const onValue = React.useMemo(() => {
if (!isChecked) return [`${label}, ${description}`];
}, [onChange]);
const checkedValue = React.useCallback(
(e: React.ChangeEvent<HTMLInputElement>) =>
onChange?.(onValue, e.target.value),
[onChange]
);
return (
<div className="space-y-5">
<div className="relative flex items-start">
<div key={id} className="flex h-5 items-center">
<input
id={`${label}-id`}
name={label}
type="radio"
className="h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-500"
onBlur={checkedValue)}
onChange={() => setIsChecked(!isChecked)}
/>
</div>
<div className="ml-3 text-sm">
<label
htmlFor={`${label}-id`}
className="block font-medium text-gray-700"
>
{label}
</label>
<p id={`${label}-description`} className="text-gray-500">
{description}
</p>
</div>
</div>
</div>
);
};

Import password filed as an functional component in ReactJs

I want to store this react hook and password field in a separate js file and I want to import it to my register form how can I do that?
Password Field
<label class="font-medium block mb-1 mt-6 text-gray-700" for="password">
Password
</label>
<div class="relative w-full">
<div class="absolute inset-y-0 right-0 flex items-center px-2">
<input class="hidden js-password-toggle" id="toggle" type="checkbox" />
<label class="bg-gray-300 hover:bg-gray-400 rounded px-2 py-1 text-sm text-gray-600 font-mono cursor-pointer js-password-label" for="toggle">show</label>
</div>
<input class="appearance-none border-2 rounded w-full py-3 px-3 leading-tight border-gray-300 bg-gray-100 focus:outline-none focus:border-indigo-700 focus:bg-white text-gray-700 pr-16 font-mono js-password" id="password" type="password" autocomplete="off"
/>
</div>
Password function filed
useEffect(() => {
const passwordToggle = document.querySelector('.js-password-toggle')
passwordToggle.addEventListener('change', function() {
const password = document.querySelector('.js-password'),
passwordLabel = document.querySelector('.js-password-label')
if (password.type === 'password') {
password.type = 'text'
passwordLabel.innerHTML = 'hide'
} else {
password.type = 'password'
passwordLabel.innerHTML = 'show'
}
password.focus()
})
}, [])
Form That I want to add this password filed
import React, { useEffect, useState } from "react";
import Buttons from "../../../elements/form/Button";
import PasswordInput from "../../../elements/form/PasswordInput";
import { Col, Input, Row, Select, Form, InputNumber, Divider } from "antd";
import { ChangePassword, sentOtp, changePhoneNumber, requestOtp } from "./SecurityApi";
const { Option } = Select;
const Security = () => {
const [phoneNo, setPhoneNo] = useState("");
const [otp, setOtp] = useState("");
//const [password, setPassword] = useState("");
const [conPassword, setConPassword] = useState("");
const [passError, setPassError] = useState();
const [otpError, setOtpError] = useState();
const [user, setUser] = useState(null);
//changing password
const [editPasswordState, setEditPasswordState] = useState(false);
const [password, setPassword] = useState({
password: "",
});
const handlePasswordChange = async () => {
if (password === user.password) {
return;
}
if (password.trim() === "") {
console.log("cant be empty");
return;
}
await ChangePassword(password, setUser);
};
useEffect(() => {
setPassError(password && conPassword && password !== conPassword);
}, [password, conPassword]);
useEffect(() => {
setOtpError(!otp && phoneNo);
}, [otp]);
//onSubmit password
const onSubmit = async () => {
if (passError) return false;
try {
const res = await ChangePassword({ password });
setPassword("");
setConPassword("");
alert("Password Changed !!");
} catch (error) {
alert("Something went wrong !!");
}
};
//OTP
const sendOtp = async () => {
if (phoneNo === "") return false;
try {
const res = await sentOtp(phoneNo);
alert(`Otp is ${res} !!`);
} catch (error) {
alert("Something went wrong !!");
}
};
//Changing the phone number
const changePhoneNo = async () => {
if (phoneNumber === "") return false;
if (otp === "") {
setOtpError(true);
return false;
}
try {
const res = await changePhoneNumber(phoneNo);
setPhoneNumber("");
setOtp("");
alert("Phone Number Changed !!");
} catch (error) {
alert("Something went wrong !!");
}
};
const [editPhoneNumberState, setEditPhoneNumberState] = useState(false);
const [phoneNumber, setPhoneNumber] = useState({
password: "",
});
const handlePhoneNumberChange = async () => {
if (phoneNumber === user.phoneNumber) {
return;
}
if (password.trim() === "") {
console.log("cant be empty");
return;
}
await ChangePassword(password, setUser);
};
return (
<>
<div className="md:pl-8 sm:pl-0 ">
{/* ---------- Password Change ------------ */}
<div class="mt-10 sm:mt-0">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">
Change Password
</h3>
<p class="mt-1 text-sm text-gray-600">Change password here</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form action="#" method="POST">
<div class="shadow overflow-hidden sm:rounded-md">
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<Buttons
title={
!editPasswordState ? "Edit Full Password" : "Cancel"
}
outline
onClick={() => {
setEditPasswordState(!editPasswordState);
}}
class="inline-flex
justify-center
py-2 px-4 border
border-transparent
shadow-sm text-sm
font-medium rounded-md
text-white bg-red-400
hover:bg-red-400
focus:outline-none f
ocus:ring-2
focus:ring-offset-2
focus:ring-red-500"
/>
</div>
<div class="col-span-6 sm:col-span-3">
{editPasswordState && (
<Buttons
title="Save"
onClick={async () => {
setEditPasswordState(false);
await handlePasswordChange();
}}
/>
)}
</div>
</div>
</div>
<div class="px-4 py-5 bg-white sm:p-6">
{/* OTP Check*/}
<div class="grid grid-cols-6 gap-1">
<div class="col-span-4 sm:col-span-3">
<label
for="first-name"
class="block text-sm font-medium text-gray-700"
>
Send OTP
</label>
<Buttons
title={"Request OTP"}
outline
onClick={async () => {
await requestOtp(user.phoneNumber);
}}
/>
</div>
<div class="col-span-6 sm:col-span-3">
<label
for="last-name"
class="block text-sm font-medium text-gray-700"
>
Enter OTP
</label>
<input
type="text"
name="last-name"
id="last-name"
autocomplete="family-name"
class="mt-1
focus:ring-red-400
focus:border-red-400
block w-full
shadow-sm sm:text-sm
border-gray-300 rounded-md"
/>
{passError && (
<Col className="text-red-500">
OTP doesn't Correct !!
</Col>
)}
</div>
</div>
{/* OTP Check End */}
</div>
<div class="px-4 py-5 bg-white sm:p-6">
{/* Password Check*/}
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<label
for="first-name"
class="block text-sm font-medium text-gray-700"
>
New Password
</label>
<Input.Password
value={password}
onChange={(event) => {
setPassword(event.target.value);
}}
class="mt-1
focus:ring-red-400
focus:border-red-400
block w-full
shadow-sm sm:text-sm
border-gray-300 rounded-md"/>
This is the Place
</div>
<div class="col-span-6 sm:col-span-3">
<label
for="last-name"
class="block text-sm font-medium text-gray-700"
>
Confirm New Password
</label>
<Input.Password
value={conPassword}
onChange={(event) => {
setConPassword(event.target.value);
}}
/>
{passError && (
<Col className="text-red-500">
Password doesn't match !!
</Col>
)}
</div>
</div>
{/* Password Check End*/}
</div>
</div>
</form>
</div>
</div>
</div>
{/* ------- End Password Change -------- */}
<div class="px-4 py-1 bg-black-50 text-right sm:px-6">
<Divider></Divider>
</div>
{/* ------------ Mobile Number Change ---------------- */}
<div class="mt-10 sm:mt-0">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">
Change Mobile Number
</h3>
<p class="mt-1 text-sm text-gray-600">
Use a permanent address where you can receive mail.
</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form action="#" method="POST">
<div class="shadow overflow-hidden sm:rounded-md">
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<Buttons
title={
!editPhoneNumberState ? "Edit Phone Number" : "Cancel"
}
outline
onClick={() => {
setEditPhoneNumberState(!editPhoneNumberState);
}}
className={" flex items-center justify-center "}
/>
</div>
<div class="col-span-6 sm:col-span-3">
{editPhoneNumberState && (
<Buttons
title="Save"
onClick={async () => {
setEditPhoneNumberState(false);
await handlePhoneNumberChange();
}}
/>
)}
</div>
</div>
</div>
<div/>
<div class="px-4 py-5 bg-white sm:p-6">
{/** Email Verification */}
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<label
for="first-name"
class="block text-sm font-medium text-gray-700"
>
Email
</label>
<Buttons
title="Send Email"
onClick={sendOtp}
outline
class=" inline-flex
justify-center
py-2 px-4 border
border-transparent
shadow-sm text-sm
font-medium rounded-md
text-white bg-red-400
hover:bg-red-400
focus:outline-none f
ocus:ring-2
focus:ring-offset-2
focus:ring-red-500"
/>
</div>
<div class="col-span-6 sm:col-span-3">
<label
for="last-name"
class="block text-sm font-medium text-gray-700"
>
Verification Code
</label>
<input
type="text"
name="last-name"
id="last-name"
autocomplete="family-name"
class="mt-1
focus:ring-red-400
focus:border-red-400
block w-full
shadow-sm sm:text-sm
border-gray-300 rounded-md"
/>
</div>
</div>
{/** End Email Verification */}
{/** Phone Number change */}
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<label
for="first-name"
class="block text-sm font-medium text-gray-700"
>
New Mobile Number
</label>
<input
type="text"
name="first-name"
id="first-name"
autocomplete="given-name"
class="mt-1
focus:ring-red-400
focus:border-red-400
block w-full
shadow-sm sm:text-sm
border-gray-300 rounded-md"
/>
</div>
</div>
{/** End Email change */}
</div>
</div>
</form>
</div>
</div>
</div>
{/* ------------ Mobile Number Change ---------------- */}
</div>
</>
);
};
export default Security;
Above mention between two section, the password field should be added
Ok, lets assume this is your form:
import PasswordField from "/PasswordField"
const Form = () => {
const [password, setPassword] = useState("")
const [name, setName] = useState("")
const [lastName, setLastName] = useState("")
const submitForm = () => {
//your logic for submitting form
}
return (
<form onSubmit={submitForm}>
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
<input type="text" value={lastName} onChange={(e) => setLastName(e.target.value)} />
<PasswordField password={password} setPassword={setPassword} />
</form>
);
};
export default Form;
Note we are importing the PasswordField component to be used inside the form, and passing the value and the function to change that value as props to the PasswordField component.
Now lets create the Password component:
import React, {useState} from 'react';
const PasswordField = (props) => {
return (
<div>
<label class="font-medium block mb-1 mt-6 text-gray-700" for="password">
Password
</label>
<input id={"password"} type="password" value={props.password} onChange={(e) => props.setPassword(e.target.value)} />
</div>
);
};
export default PasswordField;
Obviously, you need to add your classes and styling accordingly, but I thing this could get you going.

Warning after signup and login in ReactJS

Since I am new to ReactJS, I can't able to find why I am getting this "Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function." after signing up and loging in. Here is my code as follows:
AuthContext.js:
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";
const AuthContext = React.createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [loading, setLoading] = useState(true);
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
login,
signup,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
Signup.js:
import React, { useRef, useState } from "react";
import { useAuth } from "../contexts/AuthContext";
import { Link, useHistory } from "react-router-dom";
export default function Signup() {
const emailRef = useRef();
const passwordRef = useRef();
const passwordConfirmRef = useRef();
const { signup } = useAuth();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const history = useHistory();
async function handleSubmit(e) {
e.preventDefault();
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match");
}
try {
setError("");
setLoading(true);
await signup(emailRef.current.value, passwordRef.current.value);
history.push("/login");
} catch (e) {
console.error(e);
}
setLoading(false);
}
return (
<div>
<div
className="h-screen overflow-hidden flex
items-center justify-center bg-blue-300"
>
<form
onSubmit={handleSubmit}
className="space-y-5 bg-white p-16 rounded shadow w-2/3"
>
<h2 className="text-3xl mb-5 text-center text-gray-800">Sign Up</h2>
<hr />
<div class="bg-teal-200 relative text-teal-600 py-3 px-3 rounded-lg">
{error}
</div>
<label
htmlFor="email"
className="block mb-1 font-mono mt-3 text-gray-500"
>
Email
</label>
<input
ref={emailRef}
type="email"
name="email"
placeholder="Email"
className="w-full border-2 border-gray-200 p-3
rounded outline-none focus:border-blue-300"
required
/>
<label
htmlFor="password"
className="block mb-1 font-mono mt-3 text-gray-500"
>
Password
</label>
<input
ref={passwordRef}
type="password"
name="password"
placeholder="Password"
className="w-full border-2 border-gray-200 p-3
rounded outline-none focus:border-blue-300"
required
/>
<label
htmlFor="confirm password"
className="block mb-1 font-mono mt-3 text-gray-500"
>
Confirm Password
</label>
<input
ref={passwordConfirmRef}
type="password"
name="confirm-password"
placeholder="Retype Password"
className="w-full border-2 border-gray-200 p-3
rounded outline-none focus:border-blue-300"
required
/>
<hr />
<button
disabled={loading}
type="submit"
className="block w-full bg-pink-400 hover:bg-pink-300 p-4
rounded text-blck transition duration-300 font-semibold"
>
SIGN UP
</button>
<div className="w-100 text-center mt-2">
Already have an account?{" "}
<Link className="text-blue-600" to="/login">
Log In
</Link>
</div>
</form>
</div>
</div>
);
}
Login.js:
import React, { useRef, useState } from "react";
import { useAuth } from "../contexts/AuthContext";
import { Link, useHistory } from "react-router-dom";
export default function Login() {
const emailRef = useRef();
const passwordRef = useRef();
const { login } = useAuth();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const history = useHistory();
async function handleSubmit(e) {
e.preventDefault();
try {
setError("");
setLoading(true);
await login(emailRef.current.value, passwordRef.current.value);
history.push("/appointments");
} catch (e) {
console.error(e);
}
setLoading(false);
}
return (
<div>
<div
className="h-screen overflow-hidden flex
items-center justify-center bg-blue-300"
>
<form
onSubmit={handleSubmit}
className="space-y-5 bg-white p-16 rounded shadow w-2/3"
>
<h2 className="text-3xl mb-5 text-center text-gray-800">Log In</h2>
<hr />
<div class="bg-teal-200 relative text-teal-600 py-3 px-3 rounded-lg">
{error}
</div>
<label
htmlFor="email"
className="block mb-1 font-mono mt-3 text-gray-500"
>
Email
</label>
<input
ref={emailRef}
type="email"
name="email"
placeholder="Email"
className="w-full border-2 border-gray-200 p-3
rounded outline-none focus:border-blue-300"
/>
<label
htmlFor="password"
className="block mb-1 font-mono mt-3 text-gray-500"
>
Password
</label>
<input
ref={passwordRef}
type="password"
name="password"
placeholder="Password"
className="w-full border-2 border-gray-200 p-3
rounded outline-none focus:border-blue-300"
/>
<button
disabled={loading}
type="submit"
className="block w-full bg-pink-400 hover:bg-pink-300 p-4
rounded text-blck transition duration-300 font-semibold"
>
LOG IN
</button>
<div className="w-100 text-center mt-2">
Need an account?{" "}
<Link className="text-blue-500" to="/register">
Sign Up
</Link>
</div>
</form>
</div>
</div>
);
}
Simply because you have not make a callback after the return in useEffet which mean, your useEffect hook should be like so:
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
if (user) {
setCurrentUser(user);
}
setLoading(false);
});
return () => unsubscribe();
}, []);

Resources