I added two handlers to my code. First, mail is entered and handleStart is started, then the user name and password are obtained from the user, and then when the button is pressed, handleFinish is activated and information assignments are made. setEmail state works but password and name states do not
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");
const history = useHistory();
const url = "http://localhost:3002/register";
const emailRef = useRef();
const passwordRef = useRef();
const usernameRef = useRef();
const handleStart = () => {
setEmail(emailRef.current.value);
}
const handleFinish = async (e) => {
e.preventDefault();
console.log("ref data", passwordRef.current.value,usernameRef.current.value)
//it works and shows values
setPassword(passwordRef.current.value);
setName(usernameRef.current.value);
console.log("state data", email, password, name)
//status values are empty except for email
try {
await axios.post(url, { email, name, password });
history.push("/");
} catch (err) { }
}
and my return (HTML) codes:
{!email ? (
<div className="input">
<input type="email" placeholder="email address" ref={emailRef} />
<button className="registerButton" onClick={handleStart}>
Get Started
</button>
</div>
) : (
<form className="input">
<input type="username" placeholder="username" ref={usernameRef} />
<input type="password" placeholder="password" ref={passwordRef} />
<button className="registerButton" onClick={handleFinish}>
Start
</button>
</form>
)}
It's better to use useState to store and get values and control element rather then using ref.
Here is the code using state, that may help you:
const App = () => {
const history = useHistory();
const url = "http://localhost:3002/register";
const [step, setStep] = useState(0)
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [username, setUsername] = useState("")
const handleStart = () => {
setStep(1)
}
const handleFinish = async (e) => {
e.preventDefault();
console.log("data: ", email, password, username)
try {
await axios.post(url, { email, name, password });
history.push("/");
} catch (err) { }
}
return (
step === 0 ? (
<div className="input">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="email address"
/>
<button className="registerButton" onClick={handleStart}>
Get Started
</button>
</div>
) : (
<form className="input">
<input
type="username"
placeholder="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="password"
value={password}
onChange={() => setPassword(e.target.value)}
/>
<button className="registerButton" onClick={handleFinish}>
Start
</button>
</form>
)
)
}
This is very well known problem, explained thousands time here,
that state changes are internally asynchronous means we wont get updated state on next line immediately, it takes time to complete execution of setPassword and setName, so next line after set state, console.log would be old values
console.log(passwordRef.current.value)
console.log(usernameRef.current.value)
this must have values, and logged on console but not password and name
this below behavior is correct, known and no issues here,
console.log("state data", email, password, name)
//status values are empty except for email
better would be, this below hack works always for me,
await axios.post(url, { email, usernameRef.current.value, passwordRef.current.value });
If you wish to do some activity based on value change for email, password, name using useEffect could be a better option. You can call API or perform any activity as an effect of those values change. Please find following code -
useEffect(() => {
await axios.post(url, { email, name, password });
history.push("/");
return () => {
// handle cancelling or other clean up
}
}, [email, password, name]);
Related
I am trying to implement the standard Supabase signup, using react-jsx, but keep getting the response:
"You must provide either an email or phone number and a password"
My code looks as follows:
const [login, setLogin] = useState('')
const [password, setPassword] = useState('')
const signUpSubmitted = () => {
supabase.auth
.signUp({ login, password })
.then((response) => {response.error ? alert(response.error.message) : setToken(response)})
.catch((err) => { alert(err)})
}
and the form:
<form id='sign-up'>
<h3>Sign Up</h3>
<label>Email:</label>
<input
type='email'
value={login}
onChange={(e) => setLogin(e.target.value)}
/>
<label>Password:</label>
<input
type='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<input onClick={signUpSubmitted} type='submit'/>
</form>
I assume the problem lies with me attempting to save the values in a state, before passing them to the database. I don't see why it should be a problem, they are both strings from what I understand, so maybe I'm way off.
According to the Supabase docs, you need to pass email instead of login.
const { data, error } = await supabase.auth.signUp({
email: 'example#email.com',
password: 'example-password',
})
I would also suggest a few other optimizations:
Move your submit handler to the <form /> in order to support submitting the form with the Enter key.
Add event.preventDefault() to your submit handler to prevent the default form browser redirection behavior.
Change your submit input to a more semantic <button />.
Link your labels and inputs together with htmlFor and id attributes for accessibility (just make sure they're unique ids).
Updated Component:
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [token, setToken] = useState();
const handleSubmit = (event) => {
event.preventDefault();
supabase.auth
.signUp({ email, password })
.then((response) => {
response.error ? alert(response.error.message) : setToken(response)
})
.catch((err) => { alert(err) });
}
return (
<form id="sign-up" onSubmit={handleSubmit}>
<h3>Sign Up</h3>
<label htmlFor="email">Email:</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<label htmlFor="password">Password:</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign Up</button>
</form>
);
I tried to pass the username and password input by using useRef() for the registration process through the register form. After click button to submit it, it said required username and password. I check the network payload at browser, it only contain email without username and password.
Below are the code
import { useRef, useState } from "react";
import "./register.scss";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Register = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [username, setUsername] = useState("");
const navigate = useNavigate();
const emailRef = useRef();
const passwordRef = useRef();
const usernameRef = useRef();
// Send email to appear password
const handleStart = () => {
setEmail(emailRef.current.value);
};
// Send username & password for membership
const handleFinish = async (e) => {
e.preventDefault();
setPassword(passwordRef.current.value);
setUsername(usernameRef.current.value);
try {
await axios.post("auth/register", { username, email, password });
navigate("/login");
} catch (err) {
console.log(err);
}
};
return (
<div className="register">
<div className="wrapper">
<div className="header">
<img src="./assets/logo.png" alt="" className="logo" />
<button className="login-btn">Sign In</button>
</div>
</div>
<div className="container">
<h1>Unlimited movies, TV shows and more</h1>
<h2>Watch anywhere. Cancel anytime.</h2>
<p>
Ready to watch? Enter your email to create or restart your membership.
</p>
{!email ? (
<div className="input">
<input type="email" placeholder="Email address" ref={emailRef} />
<button className="register-btn" onClick={handleStart}>
Get Started
</button>
</div>
) : (
<form className="input">
<input type="username" placeholder="Username" ref={usernameRef} />
<input type="password" placeholder="Password" ref={passwordRef} />
<button className="register-btn" onClick={handleFinish}>
Start
</button>
</form>
)}
</div>
</div>
);
};
export default Register;
Here are the screenshot for network payload
Payload
[Preview2
You're trying to access state that hasn't update yet.
If you're using refs, you can remove the useState hooks and change your code to something like below.
const handleFinish = async (e) => {
e.preventDefault();
try {
await axios.post("auth/register", { username: usernameRef.current.value , email: emailRef.current.value, password: passwordRef.current.value });
navigate("/login");
} catch (err) {
console.log(err);
}
Controlled components would be a better option for handling form elements imo.
https://reactjs.org/docs/forms.html#controlled-components
Firebase isn't registering my user's information.
I keep getting a warning saying: 'onAuthStateChanged' is defined but never used and
'user' is assigned a value but never used.
Also, when I enter the email and password it doesn't set to empty string even though I set my password and email both to ("").
import './App.css';
import { auth } from './firebase';
import { useState, useEffect } from 'react';
import {
signInWithEmailAndPassword,
onAuthStateChanged, //<-----Here's my problem
createUserWithEmailAndPassword,
} from 'firebase/auth';
function App() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, setUser] = useState([]); // <---------Here is the other issue
const [isSignUp, setIsSignUp] = useState(false);
useEffect(() => {
auth.onAuthStateChanged((user) => {
setUser(user);
});
});
const handleEmailChange = (e) => {
setEmail(e.target.value);
};
const handlePasswordChange = (e) => {
setPassword(e.target.value);
};
const signIn = async () => {
await signInWithEmailAndPassword(auth, email, password)
.then(() => {
setEmail('');
setPassword('');
})
.catch((error) => {
alert(error.message);
});
};
const register = async () => {
await createUserWithEmailAndPassword(auth, email, password).catch((error) =>
console.log(error.message)
);
setPassword('');
setEmail('');
};
return (
<div className="App">
{isSignUp ? (
<>
<h1>Registering...</h1>
<input
type="email"
placeholder="email"
value={email}
onChange={handleEmailChange}
/>
<input
type="password"
placeholder="password"
value={password}
onChange={handlePasswordChange}
/>
<button onClick={register}>Sign Up</button>
<button onClick={() => setIsSignUp(false)}>X</button>
</>
) : (
<>
<h1>Logging in...</h1>
<input
type="email"
placeholder="email"
value={email}
onChange={handleEmailChange}
/>
<input
type="password"
placeholder="password"
value={password}
onChange={handlePasswordChange}
/>
<button onClick={signIn}>Login</button>
<button onClick={() => setIsSignUp(true)}>Register</button>
</>
)}
</div>
);
}
export default App;
I see two mistakes.
First, you should use the modular syntax for your auth state handler:
useEffect(() => {
onAuthStateChanged((user) => { // 👈 Remove the auth. here
setUser(user);
});
});
And second, the default value of the user is an object, not an array:
const [user, setUser] = useState({});
There may be more problems, but these jumped out at me.
The actual solution to my problem was that I was in the wrong app in Firebase. Once I selected the right one from the dropdown menu it worked.
I am building my first ecommerce website. I am trying to setup a register/login/logout form with react using an axios get call to a my my mongodb database.
I am having trouble setting input values for form submission. I am pretty sure that i dont have the handle change function setup correctly. I think it would be easier to bring in user data and destruction it but i am not not sure on how to implement a spread operator.
const RegisterScreen = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleChange = (e) => {
console.log(name);
setName (e.target.name);
console.log(email);
setEmail(e.target.email);
setPassword(e.target.password)
console.log(password);
}
'''<div>
<h1>Create Account</h1>
<label htmlFor="name">Name</label>
<input
type="text"
id="name"
value={name}
placeholder="Enter name"
required
onChange={handleChange}
></input>
</div>
The 'onChange' references a single input (e.target is your input). Your input has a nameand a value. You don't have email inside your input, for example.
You must get the value of your input, not email (doesn't exists).
So, a working example will be like this:
const RegisterScreen = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleChange = (e) => {
if (e.target.name === "name") {
setName (e.target.value);
} else if (e.target.name === "email") {
setEmail(e.target.value);
} else
setPassword(e.target.value)
}
}
Or, much better:
const RegisterScreen = () => {
const [data, setData] = useState({});
const handleChange = (e) => {
const newData = {...data}
newData[e.target.name] = e.target.value
setData(newData)
}
}
A working component will be:
import React, { useState } from 'react'
const RegisterScreen = () => {
const [data, setData] = useState({});
const handleChange = (e) => {
const newData = {...data}
newData[e.target.name] = e.target.value
setData(newData)
}
return (
<div>
<h1>Create Account</h1>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
value={data.name}
placeholder="Enter name"
required
onChange={handleChange}
></input>
<input
type="password"
name='password'
value={data.password}
placeholder="Enter password"
required
onChange={handleChange}
></input>
<input
type="email"
name='email'
value={data.email}
placeholder="Enter email"
required
onChange={handleChange}
></input>
<div>
<ul>
<li>
name: {data.name}
</li>
<li>
password: {data.password}
</li>
<li>
email: {data.email}
</li>
</ul>
</div>
</div>
)
}
export default RegisterScreen
Fully working app on https://github.com/afoone/stackoverflow_answer_-70325367
I am working on my project with a backend.
and currently working on a component which performs a put request to update details of a customer bean. however, I am experiencing a weird behavior.
Component:
function UpdateCustomer(props): JSX.Element {
const history = useHistory();
const [skipCount, setSkipCount] = useState(true);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
async function formData() {
try {
const response = await axios.put<CustomerModel>(globals.adminUrls.updateCustomer + props.location.state.id, {
firstName: firstName,
LastName: lastName,
email: email,
password: password
});
const updated = response.data;
store.dispatch(customerUpdatedAction(updated));
notify.success(CUSTOMER_SccMsg.CUSTOMER_UPDATED)
}
catch (err) {
notify.error(err);
}
}
const handleSubmit = (e) => {
e.preventDefault();
formData();
}
useEffect(() => {
if (skipCount) setSkipCount(false);
if (!skipCount) formData();
}, []);
return (
<div className="custom-field">
<h2>Update Customer</h2>
<div>
<form onSubmit={handleSubmit} >
<label>First name</label>
<input type="text" name="firstName" onChange={(e) => { setFirstName(e.target.value) }} />
<label>Last name</label>
<input type="text" name="lastName" onChange={(e) => { setLastName(e.target.value) }} />
<label>Email</label>
<input type="text" name="email" onChange={(e) => { setEmail(e.target.value) }} />
<label>Password</label>
<input type="text" name="password" onChange={(e) => { setPassword(e.target.value) }} />
<input type="submit" name="submit" />
</form>
</div>
</div>
);
}
export default UpdateCustomer;
backend Service:
public void updateCustomer(#Valid int id, CustomerDto customerDto) throws DoesNotExistException {
Customer customerDao = customerMapper.toDao(customerDto);
if (!custRepo.existsById(id))
throw new DoesNotExistException("Customer does not exist");
custRepo.saveAndFlush(customerDao);
backend Controller:
#PutMapping(value = "update/customer/{id}")
#ResponseStatus(HttpStatus.ACCEPTED)
#Override
public void updateCustomer(#PathVariable int id, #RequestBody CustomerDto customerDto) throws DoesNotExistException {
adminService.updateCustomer(id, customerDto);
}
Result I am getting:
I am able to save all fields into a const apart from lastName for some reason. it behaves exactly like the other fields. however, this specific field sends null to server while other fields send the input values.
Instead of performing an update to bean it just adds this as a seperate bean.
Why is this weird?
I have an identical component for updating a company and it seems to work just fine. why does this component behave differently?
Hope someone can put a hand on the problem.
Thanks.
You put LastName in the request body, check below image:
I think there is a mistake here, it looks like should be lastName, not LastName.