I'm having a problem where my code does not want to work while redirecting to the main page which is Dashboard.js. That file is just an UI I'm working on. I'm currently working on a signup and login page. Here is the code.
Signup.js
import { Form, Button, Card, Alert } from "react-bootstrap"
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("/")
} catch {
setError("Failed to create an account")
}
setLoading(false)
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Sign Up</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required />
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" ref={passwordConfirmRef} required />
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Sign Up
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
Already have an account? <Link to="/login">Log In</Link>
</div>
</>
)
}
AuthContext.js
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)
}
function logout() {
return auth.signOut()
}
function resetPassword(email) {
return auth.sendPasswordResetEmail(email)
}
function updateEmail(email) {
return currentUser.updateEmail(email)
}
function updatePassword(password) {
return currentUser.updatePassword(password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
setLoading(false)
})
return unsubscribe
}, [])
const value = {
currentUser,
login,
signup,
logout,
resetPassword,
updateEmail,
updatePassword
}
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}
Login.js
import { Form, Button, Card, Alert } from "react-bootstrap"
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("/")
} catch {
setError("Failed to log in")
}
setLoading(false)
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Log In</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required />
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Log In
</Button>
</Form>
<div className="w-100 text-center mt-3">
<Link to="/forgot-password">Forgot Password?</Link>
</div>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
Need an account? <Link to="/signup">Sign Up</Link>
</div>
</>
)
}
App.js
import React from "react"
import Signup from "./Signup"
import { Container } from "react-bootstrap"
import { AuthProvider } from "../contexts/AuthContext"
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
import Dashboard from "./Dashboard"
import Login from "./Login"
import PrivateRoute from "./PrivateRoute"
import ForgotPassword from "./ForgotPassword"
import UpdateProfile from "./UpdateProfile"
function App() {
return (
<Container
className="d-flex align-items-center justify-content-center"
style={{ minHeight: "100vh" }}
>
<div className="w-100" style={{ maxWidth: "400px" }}>
<Router>
<AuthProvider>
<Switch>
<PrivateRoute exact path="/" component={Dashboard} />
<PrivateRoute path="/update-profile" component={UpdateProfile} />
<Route path="/signup" component={Signup} />
<Route path="/login" component={Login} />
<Route path="/forgot-password" component={ForgotPassword} />
</Switch>
</AuthProvider>
</Router>
</div>
</Container>
)
}
export default App
index.js
import ReactDOM from "react-dom"
import App from "./components/App"
import "bootstrap/dist/css/bootstrap.min.css"
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
)
The problem I'm having in this code is at the useHistory part in Login.js(Line 12 and 21) and Signup.js(Line 13 and 26). Included the other codes because I think that all of the code might be linked to one another.
Thank you.
In both login and signup scenarios you are redirecting to home page immediately after a successful call. However your context value is updating only when the onAuthStateChanged function callback is called by firebase. There can be a small lag during this time and hence you aren't able to redirect to the PrivateRoute correctly.
A reliable way of handling this would be to wait for the currentUser data to be available from context like
const { login, currentUser } = useAuth()
async function handleSubmit(e) {
e.preventDefault()
try {
setError("")
setLoading(true)
await login(emailRef.current.value, passwordRef.current.value)
} catch {
setError("Failed to log in");
}
setLoading(false)
}
useEffect(() => {
if(currentUser) {
history.push('/');
}
}, [currentUser]);
A similar handling can be done in signup component too. This way even if you try to visit the login or signup routes directly from browser url, you will be redirected to home page if the user is already logged in.
Related
I am making an app using react and ruby-on-rails. My issue is, when I use the commented out if statement (in App.js: line 31) everything works. However, when I try to use if statemen with expression (line 31), browser respond, that neither onLogin and onSignup is not a function.
App.js
import './App.css';
import HomePage from './HomePage'
import Feed from './Feed'
import Login from "./Login";
import Post from "./Post";
import Signup from './Signup';
import { Routes, Route } from "react-router-dom";
import { useState, useEffect } from 'react';
import NavBar from './NavBar';
import SearchUser from './SearchUser'
import UserPage from './UserPage'
function App() {
const [user, setUser] = useState(false) /* log in method */
const [search, setSearch] = useState([])
const [signup, setSignup] = useState(false)
useEffect(() => {
// auto-login
fetch("/me").then((r) => {
if (r.ok) {
r.json().then((user) => {
setUser(user)});
}
});
}, []);
if (!user) return(signup ? <Signup onSignup={setSignup}/> : <Login onLogin={setUser} onSignup={setSignup}/>);
// if (!user) return(<Login onLogin={setUser} />);
return (
<div className="App">
<NavBar user={user} onLogin={setUser} onSearch={setSearch} ></NavBar>
{search.length > 0 && <SearchUser users={search} clearSearch={setSearch}></SearchUser>}
<Routes>
<Route path="/feed" element={<Feed user={user}/>}></Route>
<Route path="/" element={<HomePage user={user} onLogin={setUser}/>}></Route>
<Route path="/signup" element={<Signup />}></Route>
<Route path="/login" element={<Login />}></Route>
<Route path="/posts/:id" element={<Post />}></Route>
<Route path="/users/:id" element={<UserPage userId={user.id} searched = {search} />}></Route>
</Routes>
</div>
);
}
export default App;
Login.js
import logo from './logo.svg';
import { useState } from 'react';
import { Link } from 'react-router-dom';
function Login({onLogin, onSignup}) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState([])
function handleSubmit(e) {
e.preventDefault();
fetch("/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
password,
}),
})
.then((r) => {
if(r.ok) {
setErrors([])
r.json().then((user) => {
onLogin(user)
console.log(`User: ${user.username} with id: ${user.id} has been logged in`)})
}
else {
r.json().then((err)=> setErrors(err.errors))
}
});
}
return(
<div className = "Login">
<header style={{display: "flex", flexDirection: "column", padding: "100px 500px"}}>
<section><img src={logo} style={{height: "50px", width: "50px"}} alt=""></img>Instaclone</section>
<form
onSubmit={handleSubmit}
style={{display: "flex", flexDirection: "column", margin: "50px 50px"}}>
{/* fetch error handlers for login and signup */}
{errors ?
<p>{errors}</p> :
<p></p>}
{/* fetch error handlers for login and signup */}
<label htmlFor="username">Username:</label>
<input
type="text"
id="username"
value={username}
onChange={(e) => setUsername(e.target.value)}>
</input>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}>
</input>
<button type='submit'>login</button>
<button onClick={()=>onSignup(true)}><Link to="/signup">Don't have an account?</Link></button>
</form>
</header>
</div>
);
}
export default Login;
Signup.js
import logo from './logo.svg';
import { useState } from 'react';
import { Link } from 'react-router-dom';
function Signup({onSignup}) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirmation, setPasswordConfirmation] = useState("");
const [errors, setErrors] = useState([])
function handleSubmit(e) {
e.preventDefault();
fetch("/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
password,
password_confirmation: passwordConfirmation,
}),
})
.then((r) => {
if(r.ok) {
r.json().then((user) => {
onSignup(false)
console.log(`User: ${user.username} has been created`)})
}
else {
r.json().then((err)=> setErrors(err.errors))
}
});
}
return(
<div className = "Signup">
<header style={{display: "flex", flexDirection: "column", padding: "100px 500px"}}>
<section><img src={logo} style={{height: "50px", width: "50px"}} alt=""></img>Instaclone</section>
<form
onSubmit={handleSubmit}
style={{display: "flex", flexDirection: "column", margin: "50px 50px"}}>
{/* fetch error handlers for login and signup */}
{errors.length > 0 ?
errors.map((error, index)=><p key={index}>{error}</p>) :
<p></p>}
{/* fetch error handlers for login and signup */}
<label htmlFor="username">Username:</label>
<input
type="text"
id="username"
value={username}
onChange={(e) => setUsername(e.target.value)}>
</input>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}>
</input>
<label htmlFor="password_confirmation">Confirm Password:</label>
<input
type="password"
id="password_confirmation"
value={passwordConfirmation}
onChange={(e) => setPasswordConfirmation(e.target.value)}>
</input>
<button type='submit'>Signup</button>
<button onClick={()=>onSignup(false)}><Link to="/login">I have an account!</Link></button>
</form>
</header>
</div>
);
}
export default Signup;
I think the problem is an expression that I used. However, I am not sure what might be the case as I am not getting any errors except the ones mentioned.
enter image description here
I tried to use the old statement I was using and surprisingly it works
I am working on firebase authentication. I have made login, logout(on home), home pages. All are working fine. But when I try to login after I have changed something in router or in my code it works perfectly, that is redirects to Home. But when I login after logout, It does not work and reloads the same login page.
Also when isLoggedIn is set true after first try, it reloads login component. When I manually change url to /home then it works fine.
Here is my code.
App js
import Signup from "./Signup";
import Login from "./Login";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./Home";
import ProtectedRoutes from "../ProtectedRoutes";
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/">
<Route
path="home"
element={
<ProtectedRoutes
isLoggedIn={JSON.parse(localStorage.getItem("isLoggedIn"))}
>
<Home />
</ProtectedRoutes>
}
/>
<Route path="login" element={<Login />} />
<Route path="signup" element={<Signup />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Login
import React from "react";
import { useRef, useState } from "react";
import { Button, Card, Form, Alert, Container } from "react-bootstrap";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebaserc";
import { Link, useNavigate } from "react-router-dom";
export default function Login() {
const emailRef = useRef();
const passwordRef = useRef();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
signInWithEmailAndPassword(
auth,
emailRef.current.value,
passwordRef.current.value
)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
console.log(user);
localStorage.setItem("isLoggedIn", true);
if (JSON.parse(localStorage.getItem("isLoggedIn"))) {
navigate("/home");
}
setError("");
})
.catch((error) => {
setError(error.message);
});
};
return (
<>
<Container
className="d-flex align-items-center justify-content-center"
style={{
minHeight: "100vh",
}}
>
<div
className="w-100"
style={{
maxWidth: "400px",
}}
>
<Card>
<Card.Body>
<h2 className="text-center mb-3">Login</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email" className="mb-2">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required />
</Form.Group>
<Form.Group id="password" className="mb-2">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required />
</Form.Group>
<Button disabled={loading} className="w-100 mt-2" type="submit">
Login
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
New here? <Link to="/signup">Signup</Link>
</div>
</div>
</Container>
</>
);
}
Signup
import React from "react";
import { useRef, useState } from "react";
import { Button, Card, Form, Alert, Container } from "react-bootstrap";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebaserc";
import { Link, useNavigate } from "react-router-dom";
export default function Signup() {
const emailRef = useRef();
const passwordRef = useRef();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
createUserWithEmailAndPassword(
auth,
emailRef.current.value,
passwordRef.current.value
)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
console.log(user);
setError("");
navigate("/home");
localStorage.setItem("isLoggedIn", true);
// ...
})
.catch((error) => {
setError(error.message);
// ..
});
};
return (
<>
<Container
className="d-flex align-items-center justify-content-center"
style={{
minHeight: "100vh",
}}
>
<div
className="w-100"
style={{
maxWidth: "400px",
}}
>
<Card>
<Card.Body>
<h2 className="text-center mb-3"> Sign Up</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email" className="mb-2">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required />
</Form.Group>
<Form.Group id="password" className="mb-2">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required />
</Form.Group>
<Button disabled={loading} className="w-100 mt-2" type="submit">
Sign Up
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
Already have an account <Link to="/login">Login</Link>
</div>
</div>
</Container>
</>
);
}
Home
import React from "react";
import { Button } from "react-bootstrap";
import { auth } from "../firebaserc";
import { signOut } from "firebase/auth";
import { useNavigate } from "react-router-dom";
export default function Home() {
const navigate = useNavigate();
const handleLogout = () => {
signOut(auth)
.then(() => {
// Sign-out successful.
localStorage.removeItem("isLoggedIn");
navigate("/login", { replace: true });
})
.catch((error) => {
// An error happened.
console.log(error.message);
});
};
return (
<div>
Home
<Button onClick={handleLogout}>Logout</Button>
</div>
);
}
Protected Routes
import { Navigate } from "react-router-dom";
const ProtectedRoutes = ({ isLoggedIn, children }) => {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
};
export default ProtectedRoutes;
Let's say you want to make a React App refresh ,
Simply
React.useEffect(() => {
doSomething();
}, [doSomething, IsAuthenticated ]);
once this values change it will update this component
This value need to be observable
firebase gives you that
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
https://firebase.google.com/docs/auth/web/manage-users
and with react you can also make
firebase.auth().onAuthStateChanged((user) => {
if (user) {
handleLogin(user);
} else {
Logout();
}
});
function Logout() {
setAuthintecated(false)
};
Also here some resource for you
https://www.freecodecamp.org/news/react-firebase-authentication-and-crud-operations/
GoodLuck
I'm getting two errors the first one is saying that it can destructure. it's saying the error is coming from my signup.js file
Uncaught TypeError: Cannot destructure property 'signup' of '(0 , _contexts_AuthContext__WEBPACK_IMPORTED_MODULE_1__.useAuth)(...)' as it is undefined.
at SignUp (SignUp.js:9:1)
I'm unable to see what's wrong in my signup.js file
import React, { useRef, useState } from "react";
import { Form, Button, Card, Container, Alert } from "react-bootstrap";
import { useAuth } from "../contexts/AuthContext";
function SignUp() {
const emailRef = useRef();
const passwordRef = useRef();
const passwordConfirmedRef = useRef();
const { signUp } = useAuth();
const [error, setError] = useState(" ");
const [loading, setLoading] = useState(false);
async function handleSubmit(e) {
e.preventDefault();
if (passwordRef.current.value === passwordConfirmedRef.current.value) {
return setError("Passwords do not match");
}
try {
setError("");
setLoading(true);
await signUp(emailRef.current.value, passwordRef.current.value);
} catch {
setError("Failed to create an account");
}
setLoading(false);
}
return (
<React.Fragment>
<Container
className="d-flex align-item-center justify-content-center"
style={{ minHeight: "40vh", marginTop: "10px" }}
>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Sign Up</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
ref={emailRef}
required
></Form.Control>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
ref={passwordRef}
required
></Form.Control>
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control
type="password"
ref={passwordConfirmedRef}
required
></Form.Control>
</Form.Group>
<Button
disabled={loading}
className="w-100"
type="submit"
style={{ marginTop: "20px" }}
>
Sign Up
</Button>
</Form>
</Card.Body>
</Card>
</Container>
<div className="w-100 text-center mt-2">
Already have an accoutn? Log in
</div>
</React.Fragment>
);
}
export default SignUp;
I'm also not sure i'm supposed to add the AuthProvider tag in the app.jsx file and i am supposed to unsure where to put it.
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../../firebase";
const AuthContext = React.createContext();
function useAuth() {
return useContext(AuthContext);
}
function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
function signup(email, password) {
auth.createUserWithEmailAndPassword(email, password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
});
return unsubscribe;
}, []);
const value = {
currentUser,
signup,
};
return <AuthProvider value={value}>{children}</AuthProvider>;
}
export { useAuth, AuthProvider };
createContext need to be initialized with a default value.
const AuthContext = React.createContext({
currentUser: undefined,
signup: () => {},
});
There is spell error in your code. The value you are exporting is signup and the value you are destructuring is signUp( letter U is in caps)
I'm having trouble figuring out why I'm getting this error:
TypeError: setUser is not a function login.js:43
postLogin login.js:39
when attempting to login with correct user credentials. setUser is clearly a function because it takes from useAuth() in auth.js. I'm using React Context, session storage, Flask, and sqlite for this login process.
auth.js:
import { createContext, useContext, useState } from "react";
export const AuthContext = createContext();
export const AuthProvider = function({ user, children }) {
const [currentUser, setCurrentUser] = useState(user);
const setAuth = (data) => {
sessionStorage.setItem('username', data.user.username);
sessionStorage.setItem('isAdmin', data.user.isAdmin);
setCurrentUser(data.user);
}
return (
<AuthContext.Provider value={{ currentUser, setCurrentUser: setAuth }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth(user) {
return useContext(AuthContext);
}
App.js:
import { useState, useEffect } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { AuthProvider, useAuth } from './context/auth';
import "bootstrap/dist/css/bootstrap.min.css";
/* Begin Import Components */
import NavigationBar from "./components/navbar";
import Public from "./components/public-components/public";
/* End Import Components */
function App(props) {
const user = useAuth();
return (
<AuthProvider user={user}>
<Router>
<NavigationBar />
<div className="container text-center">
<Public />
</div>
</Router>
</AuthProvider>
);
}
export default App;
login.js:
import { useState } from "react";
import { Link, Redirect } from 'react-router-dom';
import { useAuth } from '../../context/auth';
import { Col, Form, Row, Button } from 'react-bootstrap';
function Login(props) {
const [loggedIn, setLoggedIn] = useState(false);
const [isError, setIsError] = useState(false);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const { setUser } = useAuth();
let referer;
if(props.location.state !== undefined) {
referer = props.location.state.referer;
} else {
referer = "/";
}
function postLogin() {
const formData = new FormData();
formData.append('email', email);
formData.append('password', password);
fetch('/login', {
method: 'post',
body: formData
}).then(res => res.json())
.then(data => {
console.log('Login response data: ', data);
if(data.wrongPassword) {
setIsError(true);
} else {
setUser({username: data.user.username, isAdmin: data.user.isAdmin});
setLoggedIn(true);
}
}).catch(err => {
console.log(err);
setIsError(true);
});;
}
if(loggedIn) {
return <Redirect to={referer} />;
}
return (
<main>
<header>
<h2>Login</h2>
</header>
<section>
<Form>
<Row className="justify-content-sm-center">
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="email">Email</Form.Label>
<Form.Control
controlid="email"
type="email"
value={email}
onChange={e => {
setEmail(e.target.value);
}}
placeholder="Enter email"
autoFocus
/>
</Form.Group>
</Row>
<Row className="justify-content-sm-center">
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="password">Password</Form.Label>
<Form.Control
controlid="password"
type="password"
value={password}
onChange={e => {
setPassword(e.target.value);
}}
placeholder="Enter password"
/>
</Form.Group>
</Row>
<Button onClick={postLogin} variant="success">Login</Button>
</Form>
</section>
<Link to="/register">Don't have an account?</Link>
{ isError &&<p>There was a problem logging in!</p> }
</main>
)
}
export default Login;
login route from Flask backend (api.py):
#app.route("/login", methods=['POST'])
def login():
try:
email = request.form['email']
password = request.form['password']
user = db.session.query(User.username, User.password).filter_by(email=email).first()
user_role = db.session.query(UserRole.role).filter_by(username=user.username).first()
if(check_password_hash(user.password, password)):
if(user_role.role == 'Admin'):
return {'user': {'username': user.username, 'isAdmin': True}}
return {'user': {'username': user.username, 'isAdmin': False}}
else:
return {'wrongPassword':True}
except:
return 'Something went wrong...'
You named the variable: setCurrentUser not setUser see:
<AuthContext.Provider value={{ currentUser, setCurrentUser: setAuth }}>
So there is no setUser returned from the provider
For creating user authentication in react I used firebase authentication module,So I setup the firebase config file and created the authentication file and created the signup module for the creating the signup page in "react-app" folder but when I { currentUser.email} in my signup module I got the error message 'TypeError: Cannot read property 'email' of null' in the client side. This error occurs when I coded ```{ currentUser.email}`` in signup.js file in line number 36.
So I am giving up the three files, these 3 files are responsible for the creation of signup page
1.SignUp.js File
import React, { useRef, useState } from 'react'
import { Form, Button, Card, Alert} from 'react-bootstrap'
import { useAuth } from '../contexts/AuthContext'
const SignUp = () => {
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
const { Signup, currentUser } = useAuth()
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
async function handleSubmit(e) {
e.preventDefault()
if(passwordRef.current.value !== passwordConfirmRef.current.value){
return setError('Password do not match')
}
try {
setError('')
setLoading(true)
await Signup(emailRef.current.value, passwordRef.current.value)
} catch {
setError('Failed to create an account')
}
setLoading(false)
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Sign Up</h2>
{ currentUser.email}
{error && <Alert variant='danger'>{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef}
required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef}
required />
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" ref={passwordConfirmRef}
required />
</Form.Group> <br></br>
<Button disabled={loading} type="submit" className="w-100" type="submit">Sign Up</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
Already have an account? Log In
</div>
</>
)
}
export default SignUp
2. AuthContext.js File
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)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
setLoading(false)
})
return unsubscribe
}, [])
const value = {
currentUser,
signup
}
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}
3. App.js file
import React from 'react'
//import 'antd/dist/antd.css'
import Signup from './Screens/SignUp'
import Header from './components/Header'
import { Container } from 'react-bootstrap'
import { AuthProvider } from './contexts/AuthContext'
function App() {
return (
<>
<Header />
<AuthProvider>
<Container className="d-flex align-items-center justify-content-center" style={{ minHeight: '100vh' }}>
<div className='w-100' style={{ maxWidth: '400px'}}>
<Signup />
</div>
</Container>
</AuthProvider>
</>
);
}
export default App;
The error I got on the client side is like this:
If no user is logged in then currentUser is null. You should check if a user is logged in yourself.
<h2 className="text-center mb-4">Sign Up</h2>
{ currentUser ? currentUser.email : "No user"}
Try refactoring your code as shown above. If no user is logged in, it'll show "No user".