Context provider not Rendering any Component inside <AuthProvider>Childern</AuthProvider> - javascript

I am New to React and the I am Using Context For First time, I am learning about Authentication with Firebase so I working on this SignUp Component. It was Working Fine Untill I put the Code between Context.Provider and React is not Rendering anything Inside it
I also tried creating test.jsx which return Text in div to see if my SignUp component is causing error but even test is not rendering
I tried to find other article but i cannot pinpoint issue in my Code
App.js
import React from 'react'
import SignUp from "./components/SignUp";
import {Container} from 'react-bootstrap'
import { AuthProvider } from "./context/AuthContext";
function App() {
return (
<AuthProvider>
<SignUp />
</AuthProvider>
);
}
export default App;
AuthContext.js
import React, { useContext, useEffect, useState } from 'react'
import { auth } from '../firebase'
const AuthContext = React.createContext()
export function useAuth() {
return useContext(AuthContext);
};
export function AuthProvider({ childern }) {
const [currentUser, setCurrentUser] = useState();
function signUp(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user);
console.log(user)
});
return unsubscribe
},[])
const value = {
currentUser,
signUp
}
return (
<AuthContext.Provider value={value} >
{childern}
</AuthContext.Provider>
)
};
Btw SignUp is not Rendering at all It is blank page
SignUp.jsx
import React, { useRef, useState } from 'react'
import { Form, Card, Button, Alert } from 'react-bootstrap'
import { useAuth } from '../context/AuthContext';
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)
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>
{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-confrim">
<Form.Label>Password Confrimation</Form.Label>
<Form.Control type="password" ref={passwordConfirmRef} required ></Form.Control>
</Form.Group>
<Button
disbled={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? Log In
</div>
</>
)
}
React Dev Tools In Chrome
App -> AuthProvider -> Context.Provider
AuthProvider
Prop
{
"children": "<ForwardRef />"
}
Hooks
[
{
"name": "State",
"value": null
}
},
{
"name": "Effect",
"value": "ƒ () {}"
}
}
]
Context.Provider
Props
{
"value": {
"currentUser": null,
"signUp": "ƒ signUp() {}"
}
}
i have been trying to find solution but couldn't

Related

react doesn't update the data, only after reloading page

It is my Auth Login form. I have AuthContext. Let's try log in.
I've clicked "log in" button. And we see AuthContext "user" : underfind
Then click reload page, and here we go, we have logged in
Why does it work like that?
Login.js
import React, {useState} from 'react'
import {useLogin} from '../hooks/useLogin'
import { useNavigate } from 'react-router-dom'
const Login = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const {login, error, isLoading} = useLogin()
let navigate = useNavigate()
const handleSubmit = async (e) => {
e.preventDefault()
await login(email, password)
}
return(
<div className='container'>
<h1>
login page
</h1>
<form className={'d-flex flex-column'} onSubmit={handleSubmit}>
<h3>Log in</h3>
<label>Email:</label>
<input
type={'email'}
onChange={(e) => setEmail(e.target.value)}
/>
<label>Password</label>
<input
type={'password'}
onChange={(e) => setPassword(e.target.value)}
/>
<button disabled={isLoading} type={'submit'}>
Log in
</button>
{error && <div className={'error'}>
{error}
</div>}
</form>
</div>
)
}
export default Login;
useLogin.js
import { useState } from "react";
import { useAuthContext } from "./useAuthContext";
export const useLogin = () => {
const [error, setError] = useState(null)
const [isLoading, setIsLoading] = useState(null)
const {dispatch} = useAuthContext()
const login = async (email, password) => {
setIsLoading(true)
setError(null)
const response = await fetch('/api/user/login', {
method:'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email, password})
})
const json = await response.json()
if(!response.ok){
setIsLoading(false)
setError(json.error)
}
if(response.ok){
localStorage.setItem('user', JSON.stringify(json))
dispatch({type:'LOGIN', paylaod:json})
setIsLoading(false)
}
}
return {login, isLoading, error}
}
AuthContext.js
import { createContext, useReducer, useEffect } from "react";
export const AuthContext = createContext()
export const authReducer = (state, action) => {
switch(action.type){
case 'LOGIN':
return {user: action.payload}
case 'LOGOUT':
return {user:null}
default:
return state
}
}
export const AuthContextProvider = ({children}) => {
const [state, dispatch] = useReducer(authReducer, {
user:null
})
useEffect(() => {
const user = JSON.parse(localStorage.getItem('user'))
if(user){
dispatch({type:'LOGIN', payload: user})
}
}, [])
console.log('AuthContext state', state)
return(
<AuthContext.Provider value={{...state, dispatch}}>
{children}
</AuthContext.Provider>
)
}
useAuthContext.js
import { AuthContext } from "../context/AuthContext";
import { useContext } from "react";
export const useAuthContext = () => {
const context = useContext(AuthContext)
if(!context){
throw Error('useAuthContext must be used inside an AuthContextProvider')
}
return context
}
here is Navbar.js
import React from "react";
import { useAuthContext } from "../hooks/useAuthContext";
import { useLogout } from "../hooks/useLogout";
import { Link } from "react-router-dom";
const Nav = () => {
const {logout} = useLogout()
const {user} = useAuthContext()
const handleClick= () => {
logout()
}
return(
<div>
{user && (
<div className="bg-dark text-light align-item-center d-flex justify-content-between m-auto container-fluid p-2">
<span className="m-0 p-0 d-flex align-item-center">{user.email}</span>
<button className="btn btn-outline-danger" onClick={handleClick}>logout</button>
</div>
)}
{!user && (
<div className="d-flex justify-content-between">
<Link to='/'>
<button>HOME</button>
</Link>
<Link to='/login'>
<button>LOGIN</button>
</Link>
<Link to='/signup'>
<button>SIGNUP</button>
</Link>
</div>
)}
</div>
)
}
export default Nav
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { AuthContextProvider } from './context/AuthContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<AuthContextProvider>
<App />
</AuthContextProvider>
</React.StrictMode>
);
app.js
import {BrowserRouter, Routes, Route} from 'react-router-dom'
import Nav from './components/Nav';
import Home from './pages/home';
import Login from './pages/login';
import Signup from './pages/signup';
function App() {
return (
<div>
<BrowserRouter>
<Nav/>
<Routes>
<Route path={'/'} element={<Home/>}/>
<Route path={'/login'} element={<Login/>}/>
<Route path={'/signup'} element={<Signup/>}/>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
I don't think it is server error.
There's a spelling mistake in useLogin payload is written wrong
dispatch({type:'LOGIN', paylaod:json});
// Should be: Payload
dispatch({type:'LOGIN', payload:json});
The root cause seems to be a typo:
dispatch({type:'LOGIN', paylaod:json})
has a typo in paylaod, so the reducer's
case 'LOGIN':
return {user: action.payload}
basically just sets {user: undefined}.
You should add error checking to your reducer, or better yet switch to a typed language like TypeScript so typos like these are caught at type-check time.
Since the user is not in the component state, it will not re-render after it is set (which seems to happen after first rendering). Add a useEffect with dependency on the value that updates the state and it should be good. F.ex:
const Nav = () => {
const {contextUser} = useAuthContext()
const [user, setUser] = useState()
...
useEffect(() => {
if (contextUser) {
setUser(contextUser)
}
}, [contextUser])
...
}

Problem with JS functions, using Firebase and React

thanks for your patience. I'm implementing Firebase on my site but when I call the signup function in FormUp.js (declared in AuthContext.js) it doesn't refer to the function definition. This causes the function called in FormUp.js, not to call its own function defined in AuthContext.js, but falls into the catch branch ('Failed to create an account'). I don't understand why. Hope someone can help me, thanks!
Error:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_1__.auth.createUserWithEmailAndPassword is not a function
at signup (bundle.js:4226:56)
at handleSubmit (bundle.js:2575:13)
at HTMLUnknownElement.callCallback (bundle.js:41062:18)
at Object.invokeGuardedCallbackDev (bundle.js:41111:20)
at invokeGuardedCallback (bundle.js:41171:35)
at invokeGuardedCallbackAndCatchFirstError (bundle.js:41186:29)
at executeDispatch (bundle.js:45421:7)
at processDispatchQueueItemsInOrder (bundle.js:45453:11)
at processDispatchQueue (bundle.js:45466:9)
at dispatchEventsForPlugins (bundle.js:45477:7)
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.
at Navbar (http://localhost:3000/static/js/bundle.js:3361:76)
at Home
Code:
AuthContext.js
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";
import { createUserWithEmailAndPassword } from "firebase/auth";
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>
);
}
firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
//Hidden
};
const app = initializeApp(firebaseConfig);
const auth = getAuth();
export { app, auth };
FormUp.js
import React, { useRef, useState } from "react";
import { Link } from "react-router-dom";
import {
FormUser,
Input,
Label,
Subtitle,
TextWrapper,
TopLine,
FormButton,
Credentials,
HomePage,
SignInLink,
SignInText,
RedirectSignIn,
Credential,
} from "./Form.elements";
import { FaAngleLeft } from "react-icons/fa";
import { useAuth } from "../../contexts/AuthContext";
import { Alert } from "bootstrap";
const FormUp = ({
primary,
lightBg,
lightTopLine,
lightTextDesc,
buttonLabel,
description,
topLine,
}) => {
const emailRef = useRef();
const passwordRef = useRef();
const passwordConfirmRef = useRef();
const { signup } = 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 (
<>
<style>
#import
url('https://fonts.googleapis.com/css2?family=Poppins:wght#100;200;300;400;500;600;700;800;900&display=swap');
</style>
<FormUser lightBg={lightBg} onSubmit={handleSubmit}>
<TextWrapper>
<HomePage href="/">
<FaAngleLeft />
<TopLine lightTopLine={lightTopLine}>{topLine}</TopLine>
</HomePage>
<Subtitle lightTextDesc={lightTextDesc}>{description}</Subtitle>
{error && (
<h5 style={{ color: "red", paddingBottom: "30px" }}>{error}</h5>
)}
<Credentials>
<Credential id="email">
<Label>Email</Label>
<Input
ref={emailRef}
required
type="email"
placeholder="Email..."
></Input>
</Credential>
<Credential id="password">
<Label>Password</Label>
<Input
ref={passwordRef}
required
type="password"
placeholder="Password..."
></Input>
</Credential>
<Credential id="password-confirm">
<Label>Password confirmation</Label>
<Input
ref={passwordConfirmRef}
required
type="password"
placeholder="Password confirmation..."
></Input>
</Credential>
</Credentials>
<FormButton disabled={loading} type="submit" big primary={primary}>
{buttonLabel}
</FormButton>
<RedirectSignIn>
<SignInText>Already have an account?</SignInText>
<SignInLink href="/sign-in">Log in</SignInLink>
</RedirectSignIn>
</TextWrapper>
</FormUser>
</>
);
};
export default FormUp;

JS functions error using Firebase and React

Thanks for your patience. I'm implementing Firebase on my site but when I call the signup function in FormUp.js (declared in AuthContext.js) it doesn't refer to the function definition. This causes the function called in FormUp.js, not to call its own function defined in AuthContext.js, but falls into the catch branch ('Failed to create an account'). I don't understand why. Hope someone can help me, thanks!
Error:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_1__.auth.createUserWithEmailAndPassword is not a function
at signup (bundle.js:4226:56)
at handleSubmit (bundle.js:2575:13)
at HTMLUnknownElement.callCallback (bundle.js:41062:18)
at Object.invokeGuardedCallbackDev (bundle.js:41111:20)
at invokeGuardedCallback (bundle.js:41171:35)
at invokeGuardedCallbackAndCatchFirstError (bundle.js:41186:29)
at executeDispatch (bundle.js:45421:7)
at processDispatchQueueItemsInOrder (bundle.js:45453:11)
at processDispatchQueue (bundle.js:45466:9)
at dispatchEventsForPlugins (bundle.js:45477:7)
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.
at Navbar (http://localhost:3000/static/js/bundle.js:3361:76)
at Home
Code:
AuthContext.js
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";
import { createUserWithEmailAndPassword } from "firebase/auth";
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>
);
}
firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
//Hidden
};
const app = initializeApp(firebaseConfig);
const auth = getAuth();
export { app, auth };
FormUp.js
import React, { useRef, useState } from "react";
import { Link } from "react-router-dom";
import {
FormUser,
Input,
Label,
Subtitle,
TextWrapper,
TopLine,
FormButton,
Credentials,
HomePage,
SignInLink,
SignInText,
RedirectSignIn,
Credential,
} from "./Form.elements";
import { FaAngleLeft } from "react-icons/fa";
import { useAuth } from "../../contexts/AuthContext";
import { Alert } from "bootstrap";
const FormUp = ({
primary,
lightBg,
lightTopLine,
lightTextDesc,
buttonLabel,
description,
topLine,
}) => {
const emailRef = useRef();
const passwordRef = useRef();
const passwordConfirmRef = useRef();
const { signup } = 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 (
<>
<style>
#import
url('https://fonts.googleapis.com/css2?family=Poppins:wght#100;200;300;400;500;600;700;800;900&display=swap');
</style>
<FormUser lightBg={lightBg} onSubmit={handleSubmit}>
<TextWrapper>
<HomePage href="/">
<FaAngleLeft />
<TopLine lightTopLine={lightTopLine}>{topLine}</TopLine>
</HomePage>
<Subtitle lightTextDesc={lightTextDesc}>{description}</Subtitle>
{error && (
<h5 style={{ color: "red", paddingBottom: "30px" }}>{error}</h5>
)}
<Credentials>
<Credential id="email">
<Label>Email</Label>
<Input
ref={emailRef}
required
type="email"
placeholder="Email..."
></Input>
</Credential>
<Credential id="password">
<Label>Password</Label>
<Input
ref={passwordRef}
required
type="password"
placeholder="Password..."
></Input>
</Credential>
<Credential id="password-confirm">
<Label>Password confirmation</Label>
<Input
ref={passwordConfirmRef}
required
type="password"
placeholder="Password confirmation..."
></Input>
</Credential>
</Credentials>
<FormButton disabled={loading} type="submit" big primary={primary}>
{buttonLabel}
</FormButton>
<RedirectSignIn>
<SignInText>Already have an account?</SignInText>
<SignInLink href="/sign-in">Log in</SignInLink>
</RedirectSignIn>
</TextWrapper>
</FormUser>
</>
);
};
export default FormUp;
Well, the problem here is, as the error message suggest, that auth does not have a property called createUserWithEmailAndPassword. What you are searching for is not part of auth. Your code should be something like
function signup(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
instead of
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
Check this (if you are using version 8 of the SDK, then you need to use a different approach)
https://firebase.google.com/docs/auth/web/password-auth#create_a_password-based_account
My suggestion is to add a linter to your project to easily catch these issues. In this case the issue would have been immediately visible since the import of createUserWithEmailAndPassword is not used.

Removing the token from local Storage

So here I have Login functionality via local storage token. I am getting the token upon user being created in The dev tools/Application. It is redirecting me to the home as it should. The thing that is not working is this. When I try to press the logout I am getting ×TypeError: Cannot read property 'push' of undefined it is showing the error in the Logout Handler function
Context Api
import React from "react";
import { useHistory } from "react-router-dom"
const UserContext = React.createContext();
function getUserFromLocalStorage() {
return localStorage.getItem("authToken")
? JSON.parse(localStorage.getItem("authToken"))
: { username: null, token: null };
}
function UserProvider({ children }) {
const [user, setUser] = React.useState(getUserFromLocalStorage());
const history = useHistory()
const logoutHandler = () =>{
localStorage.removeItem("authToken");
setUser(user);
history.push("/")
}
return (
<UserContext.Provider
value={{ user, setUser, logoutHandler }}
>
{children}
</UserContext.Provider>
);
}
export { UserContext, UserProvider };
Login Link
import React from "react";
import { Link } from "react-router-dom";
import { UserContext } from "../../context/user";
import { useHistory } from "react-router-dom"
export default function LoginLink() {
const { user, logoutHandler } = React.useContext(UserContext);
if (user.authToken) {
return (
<button
onClick={() => {
logoutHandler();
}}
className="login-btn"
>
logout
</button>
);
}
return <Link to="/login">login</Link>;
Header
import React from 'react';
import { Link, useHistory } from "react-router-dom";
import Search from './Search';
import './Header.css'
import SearchBooks from './SearchBooks';
import LoginLink from '../Signin/LoginLink';
import CartLink from '../Cart/CartLink';
import { UserContext } from '../../context/user';
const Header = () => {
const { user } = React.useContext(UserContext);
return (
<div className='header__container'>
<Link to='/'>
<img src='/audi.png' />
</Link>
<li>
<LoginLink />
</li>
{user.authToken &&(
<CartLink />
)
}
</div>
)
}
export default Header
Login
import { useState, } from "react";
import { useHistory } from "react-router-dom"
import axios from "axios";
import { Link } from "react-router-dom";
import "./Signin.css";
const Login = () => {
const { user, setUser } = React.useContext(UserContext);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const history = useHistory()
const loginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post(
"http://localhost:5000/api/auth/login",
{ email, password },
config
);
localStorage.setItem("authToken", data.token);
setUser(user)
history.push("/");
} catch (error) {
if (error.response) {
setError(error.response.data.error);
}
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-screen">
<form onSubmit={loginHandler} className="login-screen__form">
<h3 className="login-screen__title">Login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
required
id="email"
placeholder="Email address"
onChange={(e) => setEmail(e.target.value)}
value={email}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
<Link to="/forgotpassword" className="login-screen__forgotpassword">
Forgot Password?
</Link>
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-screen__subtext">
Don't have an account? <Link to="/register">Register</Link>
</span>
</form>
</div>
);
};
export default Login;

Logout funcionality via local storage

So here I have Login funcionality via local storage token. I am getting the token upon user being created in The dev tools/Application it is redirecting me to the home that is working. The thing that is not working is this. Creating an user it is working but when it loads it should show logout instead of login, and should hide the cart Component. Where am I making a mistake
Context Api
import React from "react";
const UserContext = React.createContext();
function getUserFromLocalStorage() {
return localStorage.getItem("authToken")
? JSON.parse(localStorage.getItem("authToken"))
: { username: null, token: null };
}
function UserProvider({ children }) {
const [user, setUser] = React.useState(getUserFromLocalStorage());
const history = useHistory();
const logoutHandler = () =>{
localStorage.removeItem("user");
history.push("/")
}
return (
<UserContext.Provider
value={{ user, logoutHandler }}
>
{children}
</UserContext.Provider>
);
}
export { UserContext, UserProvider };
Login Link
import React from "react";
import { Link } from "react-router-dom";
import { UserContext } from "../../context/user";
import { useHistory } from "react-router-dom"
export default function LoginLink() {
const { user, logoutHandler } = React.useContext(UserContext);
if (user.authToken) {
return (
<button
onClick={() => {
logoutHandler();
}}
className="login-btn"
>
logout
</button>
);
}
return <Link to="/login">login</Link>;
}
Header
import React from 'react';
import { Link, useHistory } from "react-router-dom";
import Search from './Search';
import './Header.css'
import SearchBooks from './SearchBooks';
import LoginLink from '../Signin/LoginLink';
import CartLink from '../Cart/CartLink';
import { UserContext } from '../../context/user';
const Header = () => {
const { user } = React.useContext(UserContext);
return (
<div className='header__container'>
<Link to='/'>
<img src='/audi.png' />
</Link>
<li>
<LoginLink />
</li>
{user.authToken &&(
<CartLink />
)
}
</div>
)
}
export default Header
Login Component
import { useState, } from "react";
import { useHistory } from "react-router-dom"
import axios from "axios";
import { Link } from "react-router-dom";
import "./Signin.css";
const Login = () => {
const { user, setUser } = React.useContext(UserContext);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const history = useHistory()
const loginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post(
"http://localhost:5000/api/auth/login",
{ email, password },
config
);
localStorage.setItem("authToken", data.token);
setUser(user)
history.push("/");
} catch (error) {
if (error.response) {
setError(error.response.data.error);
}
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-screen">
<form onSubmit={loginHandler} className="login-screen__form">
<h3 className="login-screen__title">Login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
required
id="email"
placeholder="Email address"
onChange={(e) => setEmail(e.target.value)}
value={email}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
<Link to="/forgotpassword" className="login-screen__forgotpassword">
Forgot Password?
</Link>
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-screen__subtext">
Don't have an account? <Link to="/register">Register</Link>
</span>
</form>
</div>
);
};
export default Login;
After you login, you have only set the authToken into your localStorage and not in your Provider. You'll need to call setUser after you login in order for Header component to know user is logged in.

Categories