I am building Login and Signup pages using react and auth by using firebase.
The problem is that after successful login and signup, the application is NOT navigating the user to landing page.
I think there is something wrong with my handleLogin and handleSignup methods but, I'm to pinpoint it out.
To Login: use -> email: test#gmail.com and password: 123456
Also, there are no errors in the console and I get 200 response from firebase.
This is firebase.config.js
import firebase from "firebase";
var firebaseConfig = {
apiKey: "MY_KEY",
authDomain: "login-and-push-notification.firebaseapp.com",
projectId: "login-and-push-notification",
storageBucket: "login-and-push-notification.appspot.com",
messagingSenderId: "84083076850",
appId: "1:84083076850:web:3e9febc1341d8f7b036a6b",
};
// Initialize Firebase
const fb = firebase.initializeApp(firebaseConfig);
export default FB;
This is Login.js
const Login = (props) => {
const [user, setUser] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [emailError, setEmailError] = useState("");
const [passwordError, setPasswordError] = useState("");
const [hasAccount, setHasAccount] = useState(false);
const clearInputs = () => {
setEmail("");
setPassword("");
};
const clearErrors = () => {
setEmailError("");
setPasswordError("");
};
const handleLogin = () => {
clearErrors();
fb.auth()
.signInWithEmailAndPassword(email, password)
.then((user) => {
console.log("user", user);
props.navigation.push("/Landing");
})
.catch((error) => {
switch (error.code) {
case "auth/invalid-email":
case "auth/user-disabled":
case "auth/user-not-found":
setEmailError(error.message);
break;
case "auth/wrong-password":
setPasswordError(error.message);
break;
}
});
};
const handleSignup = () => {
clearErrors();
fb.auth()
.createUserWithEmailAndPassword(email, password)
.catch((error) => {
switch (error.code) {
case "auth/email-already-in-use":
case "auth/invalid-email":
setEmailError(error.message);
break;
case "auth/weak-password":
setPasswordError(error.message);
break;
}
});
};
const authListener = () => {
fb.auth().onAuthStateChanged((user) => {
if (user) {
clearInputs();
setUser(user);
} else {
setUser("");
}
});
};
useEffect(() => {
authListener();
}, []);
return (
<div className="login">
<div className="loginContainer">
<label>Username</label>
<input
type="text"
value={email}
autoFocus
required
onChange={(e) => setEmail(e.target.value)}
/>
<p className="errorMsg">{emailError}</p>
<label>Password</label>
<input
type="password"
value={password}
required
onChange={(e) => setPassword(e.target.value)}
/>
<p className="errorMsg">{passwordError}</p>
<div className="btnContainer">
{hasAccount ? (
<span>
<button onClick={handleLogin} type="submit">
Sign In
</button>
<p>
Don't have an account?
<span onClick={() => setHasAccount(!hasAccount)}>Sign up</span>
</p>
</span>
) : (
<>
<button onClick={handleSignup} type="submit">
Sign Up
</button>
<p>
Have an account?
<span onClick={() => setHasAccount(!hasAccount)}>Sign in</span>
</p>
</>
)}
</div>
</div>
</div>
);
};
And then I'm importing the Login component into the Home component and passing props.
import React from "react";
import Login from "../components/Login";
import Landing from "../Pages/Landing";
function Home(props) {
return (
<div>{props.user ? <Landing {...props} /> : <Login {...props} />}</div>
);
}
export default Home;
Your authListener() in Login.js is setting a state variable in the Login component, but it does not communicate the change of state back to the rest of the application.
One way to resolve this would be to move the const [user, setUser] = useState() from Login.js to Home.js, then pass setUser as a prop to <Login>. That way, when the onAuthStateChanged() gets the user object, you set it in state at the Home level.
You'd additionally change the condition statement in Home.js to be:
return (
<div>{user ? <Landing {...props} /> : <Login {...props} />}</div>
);
since user would now be a state variable in Home.js.
Once you have that working and are comfortable with it, you might consider moving all of your authentication handling into a pattern that leverages useContext(). You would create an AuthProvider component. There are several blogs on this topic, such as this one
Related
I have a question regarding firebase auth best practices. Below is some simple code which handles user login. I want to know after the user logs in, what is the best / most efficient way of storing the user information in React. I have 3 options:
Storing in state the 'user' object which comes back in the .then
Storing in a context the 'user' object which comes back in the .then
Using the auth variable from firebase-config.js which comes with the currentUser object
Thanks
import React, { useState } from "react";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebase-config";
import { useNavigate } from "react-router-dom";
const Login = () => {
const [loginEmail, setLoginEmail] = useState("");
const [loginPassword, setLoginPassword] = useState("");
const [currentUser, setCurrentUser] = useState({});
const navigate = useNavigate();
const handleLogin = () => {
signInWithEmailAndPassword(auth, loginEmail, loginPassword)
.then((user) => {
setCurrentUser(user);
navigate("/");
})
.catch((err) => {
console.log(err.code);
err.code === "auth/wrong-password"
? alert("Incorrect password")
: alert(err.code);
});
};
return (
<>
<div className="form-container">
<p>
email
<input
type="email"
onChange={(e) => {
setLoginEmail(e.target.value);
}}
/>
</p>
<p>
password
<input
type="password"
onChange={(e) => {
setLoginPassword(e.target.value);
}}
/>
</p>
<button onClick={handleLogin}>Login</button>
</div>
</>
);
};
export default Login;
I am writing unit test case for login.
I am unsure about how to test handle submit as it contains one of the service call in the form of getToken() method, it would be greate if someone can guide me through how to handle this situation.
export const getToken = (credentials) => {
const token = 'abccss';
if (
credentials.username === 'test#test.com' &&
credentials.password === '123'
) {
return token;
} else {
return null;
}
};
The above code fetches user name and password and sends it to login in handleSubmit() function
//all imports(loginservice,auth etc etc)
import './Login.scss';
const Login = () => {
const [email, setEmail] = useState('');
const [pwd, setPwd] = useState('');
const authCon = useContext(AuthContext);
const handleSubmit = (e) => {
e.preventDefault();
const token = getToken({ username: email, password: pwd });
if (token) {
authCon.login(token);
window.location.href = '/dashboard';
}
};
return (
<div className="div-login">
<div className="div-login-logo">
<img src={logo} alt="Logo"></img>
</div>
<div>
<form onSubmit={handleSubmit}>
<input
className="credentials-input"
type="email"
value={email}
placeholder="Email Address"
required
onChange={(e) => setEmail(e.target.value)}
/>
<input
className="credentials-input"
type="password"
value={pwd}
placeholder="Password"
required
onChange={(e) => setPwd(e.target.value)}
/>
<button className="login-button" type="submit">
Log In
</button>
</form>
</div>
</div>
);
};
export default Login;
Test Code
test('Submit shoud work successfully', () => {
const mockLogin = jest.fn();
const { getByRole } = render(<Login handleSubmit={mockLogin} />);
const login_button = getByRole('button');
fireEvent.submit(login_button);
expect(mockLogin).toHaveBeenCalledTimes(1);
});
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
As I am new to React, help will be appreciated.
The actual issue is handleSubmit is not a props of Login component.
Also you can't test the internal methods of a component using React testing Library, you have to move the handleSubmit method to either parent component or a common file and pass it to the login component or import it so that you can mock the method and perform the test.
Move the getToken and handleSubmit to a common file like below,
common.ts
export const getToken = (credentials:any) => {
const token = 'abccss';
if (
credentials.username === 'test#test.com' &&
credentials.password === '123'
) {
return token;
} else {
return null;
}
};
export const handleSubmit = (e:any, email:string, pwd: string) => {
e.preventDefault();
const token = getToken({ username: email, password: pwd });
if (token) {
// authCon.login(token);
window.location.href = '/dashboard';
}
};
Modify Login.ts as like below ( see below handleSubmit is not internal and its imported from common.ts file so we that we can mock it)
import React, { useContext, useState } from 'react';
import { getToken, handleSubmit } from './common';
const Login = () => {
const [email, setEmail] = useState('');
const [pwd, setPwd] = useState('');
// const authCon = useContext(AuthContext);
return (
<div className="div-login">
<div className="div-login-logo">
{/* <img src={logo} alt="Logo"></img> */}
</div>
<div>
<form onSubmit={(e) => handleSubmit(e, email, pwd)}>
<input
className="credentials-input"
type="email"
value={email}
placeholder="Email Address"
required
onChange={(e) => setEmail(e.target.value)}
/>
<input
className="credentials-input"
type="password"
value={pwd}
placeholder="Password"
required
onChange={(e) => setPwd(e.target.value)}
/>
<button className="login-button" type="submit">
Log In
</button>
</form>
</div>
</div>
);
};
export default Login;
And finally Login.test.tsx shown below
import { fireEvent, render, screen } from '#testing-library/react';
import Login from './Login';
import * as CommonModule from './common';
jest.mock('./common');
test('Submit shoud work successfully', () => {
const mockLogin = jest.spyOn(CommonModule,'handleSubmit').mockImplementation();
const { getByRole } = render(<Login />);
const login_button = getByRole('button');
fireEvent.submit(login_button);
expect(mockLogin).toHaveBeenCalledTimes(1);
});
Test Result :
I'm creating a ProtectedRoute component in React that will take a user state variable as prop.
This user is from my checkUser() func using amplify's Auth.currentAuthenticatedUser().
function App() {
const [user, setUser] = useState();
const { Auth, Hub } = useContext(AmplifyContext)
async function checkUser() {
try {
const loggedInUser = await Auth.currentAuthenticatedUser();
setUser(loggedInUser);
console.log(loggedInUser);
// get null first time?
} catch(e) {
setUser(null);
console.log(e.message);
}
}
useEffect(() => {
checkUser();
}, [Auth])
return (
<Router>
<Suspense fallback={<p>...loading...</p>}>
<Switch>
<IsUserLoggedIn user={user} loggedInPath={ROUTES.DASHBOARD} path={ROUTES.LOGIN}>
<Route path={ROUTES.LOGIN} component={Login} />
</IsUserLoggedIn>
<IsUserLoggedIn user={user} loggedInPath={ROUTES.DASHBOARD} path={ROUTES.SIGN_UP}>
<Route path={ROUTES.SIGN_UP} component={SignUp} />
</IsUserLoggedIn>
<ProtectedRoute user={user} path={ROUTES.DASHBOARD} exact>
<Route path={ROUTES.DASHBOARD} exact component={Dashboard} />
</ProtectedRoute>
<Route path={ROUTES.RESET_PW} component={ResetPw} />
<Route component={NoPage} />
</Switch>
</Suspense>
</Router>
);
}
// Protected Route Component
import { Route, Redirect } from "react-router-dom";
import * as ROUTES from '../constants/routes';
export default function ProtectedRoute({user, children, ...restProps}) {
console.log(user);
return (
<Route
{...restProps}
render={({location}) => {
if(user) {
return children;
}
if(!user) {
return (
<Redirect
to={{
pathname: ROUTES.LOGIN,
state: { from: location }
}}
/>
)
}
return null;
}}
/>
)
}
// login component
import { useState, useContext } from "react";
import { Link } from "react-router-dom";
import { useHistory } from 'react-router';
import AmplifyContext from "../context/amplify";
import * as ROUTES from '../constants/routes';
export default function Login() {
const { Auth, Hub } = useContext(AmplifyContext);
const history = useHistory();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const invalid = !username || !password;
const handleLogin = async (e) => {
e.preventDefault();
try {
// amplify Auth login
await Auth.signIn(username, password);
history.push(ROUTES.DASHBOARD);
console.log('logged in');
} catch(e) {
setError(e.message);
setPassword('');
}
}
return (
<div className="auth-container">
<h2 className="auth-title">Log In</h2>
<div className="login-form-container">
<form className="form login-form" onSubmit={handleLogin}>
<input autoFocus type="text" placeholder="username" aria-label="username" value={username} onChange={({target}) => setUsername(target.value)} />
<input type="password" placeholder="password" aria-label="password" value={password} onChange={({target}) => setPassword(target.value)} />
{error && (<p style={{color: 'red'}}>{error}</p>)}
<div className="form-action-container">
<div className="button-container">
<button disabled={invalid} className="form-button" type='submit'>Log In</button>
<p>Need an Account? <span><Link to={ROUTES.SIGN_UP}>Sign Up</Link></span></p>
</div>
<p>Forget your password? <span><Link to={ROUTES.RESET_PW}>Reset</Link></span></p>
</div>
</form>
</div>
</div>
)
}
The current problem is that the useEffect (or maybe the Auth method?) isn't updating the state and so the first time I click "login" in my login component, it returns 'null' from my protectedRoute component's as well as the main App component's console.log(user), returning null. Only after I refresh, does it change and let me get the user log as well as directed into the protectedRoute.
This is also true for my logOut scenario.
export default function Dashboard() {
const { Auth, Hub } = useContext(AmplifyContext);
const history = useHistory();
const handleLogOut = async (e) => {
e.preventDefault();
// amplify call to sign out
await Auth.signOut();
history.push(ROUTES.LOGIN);
}
return (
<div className="dashboard-container">
<h1>Welcome </h1>
<button onClick={handleLogOut}>log out</button>
</div>
)
}
I don't get logged out, nor do I get redirected unless I reload the page.
Why aren't the Auth.signOut() and the Auth.currentAuthenticatedUser() methods run like I want it to?
made her work a bit better after putting all auth related state into context provider and wrapping it around all {children} components and then using Hub to listen for changes to log out. (I had to stop using my route helper functions, so that's kind of a bummer. But it works at the moment. I will keep it as the solution). I had to use the amplify guideline for custom auth, so still not so satisfied...
Each related state variables that needs to be used in each component is using it from context (left it out for length).
// storing all state related to Authorization
import { createContext, useContext, useState } from "react";
import AmplifyContext from "./amplify";
const AuthContext = createContext();
function AuthContextProvider({ children }) {
const [formType, setFormType] = useState("signUp");
const [fullName, setFullName] = useState("");
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [authCode, setAuthCode] = useState("");
const [error, setError] = useState("");
const [user, setUser] = useState(null);
const { Auth } = useContext(AmplifyContext);
let invalid;
const checkUser = async () => {
try {
const loggedInUser = await Auth.currentAuthenticatedUser();
setUser(loggedInUser);
console.log(user);
if (user) {
setFormType("dashboard");
} else {
setUser(null);
setFormType("login");
}
} catch (e) {
console.log(e.message);
}
};
const handleSignUp = async (e) => {
e.preventDefault();
try {
// amp auth signup. attribute must match (ie: if email is needed, state var needs to be called email (not other name))
await Auth.signUp({ username, password, attributes: { email } });
console.log("signed up");
setFullName("");
setUsername("");
setEmail("");
setPassword("");
setFormType("confirmSignUp");
} catch (e) {
console.log(e.message);
setError(e.message);
}
};
const handleConfirmAuthCode = async (e) => {
e.preventDefault();
try {
// amp auth confirm sign up
await Auth.confirmSignUp(username, authCode);
setFormType("login");
} catch (e) {
console.log(e.message);
setError(e.message);
}
};
const handleLogin = async (e) => {
e.preventDefault();
try {
// amplify Auth login
await Auth.signIn(username, password);
setUsername("");
setPassword("");
console.log("logged in");
setFormType("dashboard");
} catch (e) {
setError(e.message);
setPassword("");
}
};
const handleLogOut = async (e) => {
e.preventDefault();
// amplify call to sign out
await Auth.signOut();
//set some loading or redirect?
};
return (
<AuthContext.Provider
value={{
error,
setError,
handleSignUp,
checkUser,
handleConfirmAuthCode,
handleLogin,
handleLogOut,
fullName,
setFullName,
username,
setUsername,
email,
setEmail,
password,
setPassword,
formType,
setFormType,
authCode,
setAuthCode,
invalid,
user,
setUser,
}}
>
{children}
</AuthContext.Provider>
);
}
export { AuthContextProvider, AuthContext };
// top
ReactDOM.render(
<AmplifyContext.Provider value={{ Auth, Hub }}>
<AuthContextProvider>
<App />
</AuthContextProvider>
</AmplifyContext.Provider>,
document.getElementById("root")
);
// inside the App component (not yet finished)
import { useContext, useEffect } from "react";
import AmplifyContext from "./context/amplify";
import { AuthContext } from "./context/AuthContext";
import ConfirmSignUp from "./pages/confirmSignUp";
import Login from "./pages/login";
import SignUp from "./pages/sign-up";
import Dashboard from "./pages/dashboard";
import ResetPass from "./pages/reset-pw";
function App() {
const { Hub } = useContext(AmplifyContext);
const {
formType,
setFormType,
username,
setUsername,
error,
setError,
checkUser,
handleLogOut,
} = useContext(AuthContext);
async function setAuthListener() {
Hub.listen("auth", (data) => {
switch (data.payload.event) {
case "signIn":
console.log(`${username} signed in`);
break;
case "signOut":
console.log("user signed out");
setFormType("login");
break;
default:
break;
}
});
}
useEffect(() => {
checkUser();
setAuthListener();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
{formType === "signUp" && <SignUp />}
{formType === "confirmSignUp" && <ConfirmSignUp />}
{formType === "login" && <Login />}
{formType === "dashboard" && (
<Dashboard handleLogOut={handleLogOut} />
)}
{formType === "reset" && (
<ResetPass />
)}
</>
);
}
export default App;
App Component:
import LoginForm from "./Component/LoginForm/LoginForm";
import HomePage from "./Component/HomePage/HomePage";
import { useState, useEffect } from "react";
function App() {
const user = [{ username: "admin" }, { password: "admin" }];
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
const isUserLoggedIn = localStorage.getItem("isLoggedInn");
if (isUserLoggedIn === "1") {
setIsLoggedIn(true);
}
}, []);
const loginHandler = () => {
localStorage.setItem("isLoggedInn", "1");
setIsLoggedIn(true);
};
const logoutHandler = () => {
localStorage.removeItem("isLoggedInn");
setIsLoggedIn(false);
};
// const saveData = (enteredUsername, enteredPassword) => {
// const userPassData = {
// 'username':enteredUsername,
// 'password':enteredPassword
// };
// return userPassData;
// }
return (
<div>
{!isLoggedIn && <LoginForm adminUser={user} onLogin={loginHandler} />}
{isLoggedIn && <HomePage onLogout={logoutHandler} />}
</div>
);
}
export default App;
LoginForm Component:
import styles from './LoginForm.module.css';
import { useState } from 'react';
import SignUp from '../SignUp/SignUp';
const LoginForm = (props) =>{
const [enteredUsername,setEnteredUsername] = useState('');
const [enteredPassword,setEnteredPassword] = useState('');
const [isTrue,setTrue] = useState(true);
const [isClicked,setIsClicked] = useState(false);
const onChangeHandlerUsername = event =>{
setEnteredUsername(event.target.value);
if(event.target.value === enteredUsername){
setTrue(true);
}
}
const onChangeHandlerPassword = event =>{
setEnteredPassword(event.target.value);
if(event.target.value === enteredPassword){
setTrue(true);
}
}
const onSubmitHandler = (event) =>{
event.preventDefault();
if(enteredUsername === props.adminUser[0].username && enteredPassword === props.adminUser[1].password){
props.onLogin();
console.log(enteredUsername,enteredPassword);
}
else{
setTrue(false);
setIsClicked(true);
}
}
const onClickHandler =()=>{
setIsClicked(true);
}
return(
<>
<form onSubmit={onSubmitHandler}>
<h1>Welcome</h1>
<div className={`${styles.box} ${!isTrue && styles.wrong}`}>
<h1>Login</h1>
<input type='text' value={enteredUsername} placeholder='Enter Username' className={styles.email} onChange={onChangeHandlerUsername}></input>
<input type='password' value={enteredPassword} placeholder='Enter Password' className={styles.email} onChange={onChangeHandlerPassword}></input>
<div><button className={styles.btn}>Sign In</button></div>
<div><button onClick={onClickHandler} type='button' className={styles.btn2}>Sign Up</button></div>
<div><a href='#top'>Forget Password</a></div>
</div>
</form>
{!isClicked? '' :<SignUp/>}
</>
);
}
export default LoginForm;
want to go to SignUp page when clicked on SignUp from the App component in React can some one rectify the code accordingly. Dont know where i am wrong can some one help me out.
There is SignUp button which when clicked based on the username and password if not same as that of the added user or Admin will go to the sign up page to register for the new user.
SignUp component:
import './SignUp.module.css';
const SignUp = (props) =>{
return(
<div>
<h2>SignUp page</h2>
</div>
);
}
export default SignUp;
you are having your SignUp below the Form component if you need to render only one of them based on the isClicked then you can use the ternary operator to do it.
change your code as below
<>
{isClicked ? (
<SignUp />
) : (
<form onSubmit={onSubmitHandler}>
<h1>Welcome</h1>
<div>
<h1>Login</h1>
<input
type="text"
value={enteredUsername}
placeholder="Enter Username"
onChange={onChangeHandlerUsername}
></input>
<input
type="password"
value={enteredPassword}
placeholder="Enter Password"
onChange={onChangeHandlerPassword}
></input>
<div>
<button>Sign In</button>
</div>
<div>
<button onClick={onClickHandler} type="button">
Sign Up
</button>
</div>
<div>
Forget Password
</div>
</div>
</form>
)}
</>
Also you should not be doing this
const onChangeHandlerUsername = event =>{
setEnteredUsername(event.target.value);
// This will always be false because the state change wont reflect immediately.
// Please remove this for both the username and password
if(event.target.value === enteredUsername){
setTrue(true);
}
}
This is my Signupcomponent
const SignupComponent = () => {
const [values, setValues] = useState({
username: 'silvio1',
name: 'Silvioo',
email: 'berlusconi#gmail.com',
password: '123ooo007',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
const { username, name, email, password } = values;
const user = {username, name, email, password};
await axios.post('${API)/signup', user);
};
const handleChange = name => e => {
setValues({ ...values, [name]: e.target.value });
};
const showLoading = () => (loading ? <div className="alert alert-info">Loading...</div> : '');
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
value={values.username}
onChange={handleChange('username')}
type="text"
className="form-control"
placeholder="Type your username"
/>
</div>
<div className="form-group">
<input
value={values.name}
onChange={handleChange('name')}
type="text"
className="form-control"
placeholder="Type your name"
/>
</div>
<div className="form-group">
<input
value={values.email}
onChange={handleChange('email')}
type="email"
className="form-control"
placeholder="Type your email"
/>
</div>
<div className="form-group">
<input
value={values.password}
onChange={handleChange('password')}
type="password"
className="form-control"
placeholder="Type your password"
/>
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>
{showLoading()}
{signupForm()}
</React.Fragment>;
};
export default SignupComponent;
EDIT
I changed my code(zhulien's accepted answer).
Signup page appears,I try to sign up user.
I got error
Unhandled Runtime Error
Error: Request failed with status code 404
Call Stack
createError
node_modules/axios/lib/core/createError.js (16:0)
settle
node_modules/axios/lib/core/settle.js (17:0)
XMLHttpRequest.handleLoad
node_modules/axios/lib/adapters/xhr.js (62:0)
Frontend folder
components
config.js
next.config.js
node_modules
package.json
package-lock.json
pages
My pages folder
_document.js
index.js
signin.js
signup.js
signup.js imports the code above
import Link from 'next/link';
import Layout from '../components/Layout';
import SignupComponent from '../components/frontauth/SignupComponent';
const Signup = () => {
return (
<Layout>
<h2>Signup page</h2>
<SignupComponent />
</Layout>
);
};
My next.config.js
{
APP_NAME: 'BLOG FRONTEND',
APP_DEVELOPMENT: 'http://localhost:3000',
PRODUCTION: false
}
And config.js
const { publicRuntimeConfig } = getConfig();
console.log(publicRuntimeConfig);
export const API = publicRuntimeConfig.PRODUCTION
? 'https://cryptoblog.com'
: 'http://localhost:3000';
export const APP_NAME = publicRuntimeConfig.APP_NAME;
I am new to React and React Hooks. How to solve this problem?
First of all, you're trying to access {username}(which doesn't exist) instead of the state property which is values.username. Furthermore, don't use hooks in event handlers, they should be used in the top level body of the component or in custom hooks only. Checkout this: React hooks rules.
So:
In your form you have to use the state(values) properties.
Extract useEffect hook in the main body flow of the component or BETTER remove it altogether as you're not using it properly currently. You're better of with just the simple event handler for form submit which should post the data somewhere without setting any state.
Your code could look something like:
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { API } from '../../config';
const SignupComponent = () => {
const [values, setValues] = useState({
username: 'silvio1',
name: 'Silvioo',
email: 'berlusconi#gmail.com',
password: '123ooo007',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
const { username, name, email, password } = values;
const user = {username, name, email, password};
await axios.post('${API)/signup', user);
};
const handleChange = name => e => {
setValues({ ...values, [name]: e.target.value });
};
const showLoading = () => (loading ? <div className="alert alert-info">Loading...</div> : '');
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
value={values.username}
onChange={handleChange('username')}
type="text"
className="form-control"
placeholder="Type your username"
/>
</div>
this is how it should be:
useEffect(() => {
postUser();
}, []);
not inside the function the way you have done it:
const handleSubmit = e => {
e.preventDefault();
setValues({...values});
const { username, name, email, password } = values;
const user = {username, name, email, password};
async function postUser () {
const result = await axios.post('${API)/signup', user);
};
useEffect(() => {
postUser();
}, []);
};
UseEffects aren't meant to be placed inside your functions.Just place them inside your functional component,with some value(or no value) inside your dependency array of the useEffect.These values present inside the array will trigger the useEffect whenever they get changed.