How to pass state from component to file app.js in React - javascript

I have to pass my state from Authentication.js to App.js, to make certain functionalities available to registered users.
This is my file Authentication.js
import { useState } from "react"
import MyButton from "../componens/myButton"
import styles from "../style/authentication.module.css"
import Spinner from "../componens/Spinner"
import axios from "axios"
const Authentication = () =>{
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [loading, setLoading] = useState(false)
const [registration, setRegistration] = useState(true)
const [state, setState] = useState(null)
let MyRegistration = null;
const handleSubmit = async (e) =>{
e.preventDefault()
setLoading(true)
try {
const userKey = `AIzaSyCYe1XVuJVflRie0sf1y01RNrmQ77Dmp4Q`
let urlAPI = `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${userKey}`
if (!registration) {
urlAPI = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${userKey}`
}
setEmail(email);
setPassword(password);
MyRegistration = await axios.post(urlAPI,{
email : email,
password : password,
returnSecureToken : true
})
setState(MyRegistration)
setLoading(false);
return MyRegistration
} catch (error) {
setLoading(false)
console.log(error)
}
}
return <div className={styles.formContainer}>
<h1>Authentication</h1>
<form onSubmit={handleSubmit} action="">
<p>Email</p>
<input placeholder="Your email" type="email" value={email} onChange={handleEmail} />
<p>Password</p>
<input placeholder="Your Password" type="password" value={password} onChange={handlePassword} />
{loading ? <Spinner/> :
<MyButton title={registration ? 'sign up' : 'Sign in'} handleClickButton={handleSubmit} />}
<MyButton title={registration ? 'Go to Sign in' : 'Go to sign up'} handleClickButton={changeMode}/>
</form>
</div>
}
export default Authentication;
This is my file App.js
import Home from './pages/Home';
import Book from './pages/Book'
import {Route, Switch} from 'react-router-dom';
import SavedBooks from './pages/SavedBooks';
import Header from './componens/Header';
import BookChapter from './pages/BookChapter';
import Authentication from './pages/Authentication';
import {useState} from "react";
function App(props) {
const [userData, setUserData] = useState("");
return (
<div>
<Header/>
<Switch>
<Route exact path="/" render={(props) => <Home userData={userData}/>}/>
<Route exact path="/book/:id" component={Book}/>
<Route exact path="/savedbooks" component={SavedBooks}/>
<Route exact path="/book/:id/chapter/:numero" component={BookChapter}/>
<Route exact path="/authentication" render={(props) => <Authentication setUserData={setUserData(this.state)}/> }/>
</Switch>
</div>
)
}
export default App;
But the response is: TypeError: Cannot read properties of undefined (reading 'state')

You cannot pass the state declared in Authentication.js to its parent App.js . So, you need to make a useState in App.js and pass the state and its corresponding setterFunction onto the child i.e Authentication.js. This is known as lifting up the state.
Move const [state, setState] = useState(null) to App.js
and use the state variable in App.js and pass it onto child like this
<Route exact path="/authentication" render={(props) => <Authentication state={state} setState={setState}/> }/>

Related

How to use protected routes with firebase authentication without the context api/redux? [duplicate]

I'm trying to make a private route from my login and signup pages to my dashboard page, but all the tutorials and guides that I've stumbled upon all require some sorta AuthContext thing and I didn't implement my authentication procedure using AuthContext.
I've tried different ways but none of them work and just end up giving me a blank page when I get to the dashboard page, what can I do to make it a private route? Using Firebase v9 btw.
SignUp.js
import './Signup.css'
import React, { useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { auth }from '../../../firebase';
import { createUserWithEmailAndPassword, onAuthStateChanged } from 'firebase/auth';
import { Typography, Container, TextField, Button, Alert } from '#mui/material';
const Signup = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [error, setError] = useState('');
const [user, setUser] = useState({});
const history = useHistory();
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
})
const signup = async (e) => {
e.preventDefault();
if (password !== confirmPassword) {
return setError("Passwords do not match")
}
try {
const user = await createUserWithEmailAndPassword(
auth,
email,
password
);
history.push("/dashboard/canvas");
} catch (err) {
setError(err.message);
}
}
return (
<>
<div className="text-div">
<Typography textAlign="center" variant="h3">Create a new account</Typography>
</div>
<Container className="cont" maxWidth="xl" sx={{ backgroundColor: "#ffffff", width: 500, height: "auto", borderRadius: 4, marginTop: 5, display: "flex", flexDirection: "column", padding: 5, }}>
{ error && <Alert severity="error">{error}</Alert> }
<TextField label="Email" margin="dense" type="email" onChange={ (e) => {
setEmail(e.target.value);
}}/>
<TextField label="Password" margin="dense" type="password" onChange={ (e) => {
setPassword(e.target.value);
}}/>
<TextField label="Confirm Password" margin="dense" type="password" onChange={ (e) => {
setConfirmPassword(e.target.value);
}}/>
<Button onClick={signup} variant="contained" sx={{ marginTop: 2, }}>Sign Up</Button>
<div>
Already have an account? <Link to="/login" style={{ color: '#000' }}>Log In</Link>
</div>
</Container>
</>
)
}
export default Signup;
Login.js
import './Login.css'
import React, { useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth }from '../../../firebase';
import { Typography, Container, TextField, Button, Alert } from '#mui/material';
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const history = useHistory();
const login = async () => {
try {
const user = await signInWithEmailAndPassword(
auth,
email,
password
);
//alert("Success, user is recognized");
history.push("/dashboard/canvas");
} catch (err) {
setError("The email or password you entered is incorrect");
}
}
return (
<>
<div className="text-div">
<Typography textAlign="center" variant="h3">Login</Typography>
</div>
<Container className="cont" maxWidth="xl" sx={{ backgroundColor: "#ffffff", width: 500, height: "auto", borderRadius: 4, marginTop: 5, display: "flex", flexDirection: "column", padding: 5, }}>
{ error && <Alert severity="error">{error}</Alert> }
<TextField label="Email" margin="dense" type="email" onChange={(e) => {
setEmail(e.target.value);
}}/>
<TextField label="Password" margin="dense" type="password" onChange={(e) => {
setPassword(e.target.value);
}}/>
<Button onClick={login} variant="contained" sx={{ marginTop: 2, }}>Login</Button>
<div>
Don't have an account? <Link to="/signup" style={{ color: '#000' }}>Create one here</Link>
</div>
<div>
<Link to="/request-password-reset" style={{ color: '#000' }}>Forgot your password?</Link>
</div>
</Container>
</>
)
}
export default Login;
firebase.js
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey,
authDomain,
projectId,
storageBucket,
messagingSenderId,
appId,
measurementId
}
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export {
auth
};
App.js
import './App.css';
import Home from './components/Pages/Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Signup from './components/Pages/Signup/Signup';
import Login from './components/Pages/Login/Login';
import UserDashboard from './components/Pages/UserDashboard/UserDashboard';
import ForgotPassword from './components/Pages/Forgot-Password';
function App() {
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/signup" component={Signup}/>
<Route path="/login" component={Login}/>
<Route path="/dashboard" component={UserDashboard}/>
<Route path="/request-password-reset" component={ForgotPassword}/>
</Switch>
</div>
</Router>
);
}
export default App;
If you are trying to create a private route component without persisting the authentication state somewhere in your app and exposed out via a React context then you will need to check the auth status asynchronously on each route change. This means you'll also need a "loading" or "pending" state while the auth status check occurring.
Here's an example implementation of just a custom private route sans any persisted state.
import { useEffect, useState } from 'react';
import { Route, Redirect } from 'react-router-dom'; // v4/5
import { onAuthStateChanged } from 'firebase/auth';
import { auth }from '../../../firebase';
const PrivateRoute = props => {
const [pending, setPending] = useState(true);
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsubscribe = onAuthStateChanged(
auth,
user => {
setCurrentUser(user);
setPending(false);
},
error => {
// any error logging, etc...
setPending(false);
}
);
return unsubscribe; // <-- clean up subscription
}, []);
if (pending) return null; // don't do anything yet
return currentUser
? <Route {...props} /> // <-- render route and component
: <Redirect to="/login" />; // <-- redirect to log in
};
react-router-dom#6
Custom route components are out in v6, use a layout route. The PrivateRoute component will replace Route with Outlet for nested routes to render their matched element prop into, and Navigate replaces Redirect.
import { useEffect, useState } from 'react';
import { Outlet, Navigate } from 'react-router-dom'; // v4/5
import { onAuthStateChanged } from 'firebase/auth';
import { auth }from '../../../firebase';
const PrivateRoute = props => {
const [pending, setPending] = useState(true);
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsubscribe = onAuthStateChanged(
auth,
user => {
setCurrentUser(user);
setPending(false);
},
error => {
// any error logging, etc...
setPending(false);
}
);
return unsubscribe; // <-- clean up subscription
}, []);
if (pending) return null; // don't do anything yet
return currentUser
? <Outlet /> // <-- render outlet for routes
: <Navigate to="/login" replace />; // <-- redirect to log in
};
Wrap the routes you want to protect.
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
<Route path="/request-password-reset" element={<ForgotPassword />} />
<Route element={<PrivateRoute />}>
<Route path="/dashboard" element={<UserDashboard />} />
</Route>
</Routes>
</Router>
);
}

React Router Dom & Firebase Auth: history.push changes url but does not render new component when called after firebase auth create account

What I am trying to do
I'm using Firebase v9 and React-router-dom v5.3.0 to make a sign up form which creates a new account and redirects the user to the home screen when an account is created. The route for the home screen is "/".
The problem
My plan is to call history.push("/") after calling the sign up function, which should take me to the home screen. However, when running the code, history.push("/") only updated the URL and did not redirect me to the home screen. I had to reload the page for the home screen to show up, otherwise I'd just be stuck in the sign up form. I have been fiddling with the code and what surprises me is when I remove await signup(email, password), history.push works just as intended. I suspect this behavior has something to do with firebase's sign up function, but I don't know what it is. Can someone offer an explanation?
The code
Here's my code for the sign up form:
import { useState } from "react";
import { useHistory } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";
function Signup() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [cfPassword, setCfPassword] = useState("");
const {signup} = useAuth();
const history = useHistory();
async function handleSubmit(e) {
e.preventDefault();
if (password !== cfPassword) {
console.log("Passwords do not match!");
return;
}
try {
await signup(email, password);
history.push("/"); // Problematic code is here. This works fine when I remove the previous line.
} catch (error) {
console.log(error.message);
}
}
return (
<div>
<h1>Create an account</h1>
<form onSubmit={handleSubmit}>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email"/>
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password"/>
<input type="password" value={cfPassword} onChange={(e) => setCfPassword(e.target.value)} placeholder="Confirm Password"/>
<input type="submit" value="Sign up"/>
</form>
</div>
);
}
export default Signup;
The code containing the authentication context and the related function for signing up:
import { auth } from "../firebase";
import { useState, useEffect, useContext, createContext } from "react";
import { createUserWithEmailAndPassword } from "firebase/auth";
const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({children}) {
const [currentUser, setCurrentUser] = useState();
const [isLoading, setIsLoading] = useState(true);
function signup(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
const value = {
currentUser,
signup
}
useEffect(() => {
const unsubscriber = onAuthStateChanged(auth, (user) => {
setIsLoading(true);
setCurrentUser(user);
setIsLoading(false);
});
return unsubscriber;
}, []);
return (
<AuthContext.Provider value={value}>
{!isLoading && children}
</AuthContext.Provider>
);
}
My App.jsx component containing the router.
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { AuthProvider } from './contexts/AuthContext';
import Home from './pages/mains/home/Home';
import Signup from './components/Signup';
function App() {
return (
<AuthProvider>
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/signup" component={Signup} />
</Switch>
</Router>
</AuthProvider>
)
}
export default App;
So, after testing and revising my code, I found out that the problem lies in setIsLoading(true) in AuthProvider's useEffect. Remove that line and everything works like a charm. Hopefully this helps someone experiencing the same problem. :)
Issue
Yes, I see now where an issue lies with using the isLoading state to conditionally render the entire app. After creating a new user it seems the onAuthStateChanged handler is invoked and current user is reloaded. When toggling the isLoading state true the AuthContext's children are unmounted.
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [isLoading, setIsLoading] = useState(true);
function signup(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
const value = {
currentUser,
signup
}
useEffect(() => {
const unsubscriber = onAuthStateChanged(auth, (user) => {
setIsLoading(true); // <-- setting true
setCurrentUser(user);
setIsLoading(false);
});
return unsubscriber;
}, []);
return (
<AuthContext.Provider value={value}>
{!isLoading && children} // <-- unmounts children
</AuthContext.Provider>
);
}
Solution
A more practical solution is to add the isLoading state to the context value and create a protected route component that handles conditionally rendering null or a loading indicator, or the routed component or a redirect to log in.
Example:
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [isLoading, setIsLoading] = useState(true);
function signup(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
useEffect(() => {
const unsubscriber = onAuthStateChanged(auth, (user) => {
setIsLoading(true);
setCurrentUser(user);
setIsLoading(false);
});
return unsubscriber;
}, []);
const value = {
currentUser,
isLoading,
signup
}
return (
<AuthContext.Provider value={value}>
{children} // <-- keep children mounted!
</AuthContext.Provider>
);
}
...
const ProtectedRoute = props => {
const location = useLocation();
const { currentUser, isLoading } = useAuth();
if (isLoading) {
return null;
}
return currentUser
? <Route {...props} />
: (
<Redirect
to={{
pathname: "/login",
state: { from: location } // <-- used to redirect back after auth
}}
/>
);
};
...
function App() {
return (
<AuthProvider>
<Router>
<Switch>
<ProtectedRoute path="/somethingToProtect" component={<Private />} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<Route path="/" component={Home} />
</Switch>
</Router>
</AuthProvider>
)
}

I've created a request method, but the admin needs to login first before acquiring the token

I've created a request method so I can easily fetch it, but when I first run it, I recevied this message.
TypeError: Cannot read properties of null (reading 'user')
I know where I get this, it's because my program automatically calls it when I start it automatically.
So what I want is to stop running these codes as long as I'm not logged in.
login.jsx
import { useState } from "react"
import { useDispatch } from "react-redux"
import { useHistory } from "react-router"
import { login } from "../../redux/apiCalls"
const Login = () => {
let history = useHistory()
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const dispatch = useDispatch()
const handleClick = (e) =>{
e.preventDefault()
login(dispatch,{username,password})
history.push('/home')
}
return (
<div style={{display: 'flex', alignItems:"center", justifyContent:"center", height: '100vh', flexDirection: "column"}}>
<form action="">
<input style={{padding: 10, marginBottom:20}} value={username} type="text" placeholder="username" onChange={e => setUsername(e.target.value)} />
<input style={{padding: 10, marginBottom:20}} value={password} type="password" placeholder="password" onChange={e => setPassword(e.target.value)} />
<button style={{padding: 10, width: 100}} onClick={handleClick}>Login</button>
</form>
</div>
)
}
export default Login
requestMethod.jsx
import axios from 'axios'
const BASE_URL = 'http://localhost:5000/api'
const TOKEN =
JSON.parse(JSON.parse(localStorage.getItem('persist:root')).user).currentUser
.accessToken || null
export const publicRequest = axios.create({
baseURL: BASE_URL,
})
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
})
app.js
import { useSelector } from 'react-redux'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import PrivateRoute from '../src/components/PrivateRoute'
import './App.css'
// import Sidebar from './components/sidemenu/Sidebar'
import Home from './pages/home/Home'
import Login from './pages/login/Login'
function App() {
const admin = useSelector((state) => state.user?.currentUser?.isAdmin)
return (
<Router>
<Switch>
<Route exact path="/login" component={Login} />
<PrivateRoute path="/home" auth={admin} component={Home}></PrivateRoute>
</Switch>
</Router>
)
}
export default App

Login Form React JS With Custom Hook

I'm currently in the process of learning React JS.Tutorial D.O
I already have a PHP backend before and I want to create a login form where the result of the backend is JWT.
I use a custom hook in React JS for that.
Here is the code that I created.
App.js
import "./App.css";
import React from "react";
import { Routes } from "../config";
import { useToken } from "../hooks";
import Login from "./Login";
const App = () => {
const { token, setToken } = useToken();
if (!token) {
return <Login setToken={setToken} />;
}
return <Routes />;
};
export default App;
useToken()
import { useState } from "react";
export default function useToken() {
const getToken = () => {
const tokenString = localStorage.getItem("token");
const userToken = JSON.parse(tokenString);
return userToken?.token;
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken) => {
localStorage.setItem("token", JSON.stringify(userToken));
setToken(userToken.token);
};
return {
setToken: saveToken,
token,
};
}
Login/index.js
import React, { useState } from "react";
import PropTypes from "prop-types";
import { Button, Card, Col, Container, Form, Row } from "react-bootstrap";
import "./login.css";
async function loginUser(credentials) {
const url = "v1/auth";
const user = new FormData();
user.append("username", credentials.username);
user.append("password", credentials.password);
return fetch(url, {
method: "POST",
body: user,
}).then((data) => data.json());
}
export default function Login({ setToken }) {
const [username, setUserName] = useState();
const [password, setPassword] = useState();
// Handle submit
const handleSubmit = async (e) => {
e.preventDefault();
const token = await loginUser({ username, password });
setToken(token);
};
return (
<div id="login-page">
<Container>
<Row className="d-flex justify-content-md-center align-items-center vh-100">
<Col sm={12} md={6}>
<Card>
<Form onSubmit={handleSubmit}>
<Card.Header>Sign In</Card.Header>
<Card.Body>
<Form.Group controlId="loginform-username">
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
placeholder="Username"
name="username"
onChange={(e) => setUserName(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="loginform-password">
<Form.Label>Password</Form.Label>
<Form.Control
name="password"
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Group>
</Card.Body>
<Card.Footer>
<Button
variant="primary"
type="submit"
className="float-right"
>
Login
</Button>
<div className="clearfix"></div>
</Card.Footer>
</Form>
</Card>
</Col>
</Row>
</Container>
</div>
);
}
Login.propTypes = {
setToken: PropTypes.func.isRequired,
};
When I login successfully, I save the token to local storage. But I got the following warning.
index.js:1 Warning: Failed prop type: The prop `setToken` is marked as required in `Login`, but its value is `undefined`.
How to solve this?. Any help it so appreciated
Updated
Routes
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Login, Home } from "../../pages";
const Routes = () => {
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
};
export default Routes;
In Routes you call Login but never pass it setToken, which is required. One option is to pass the setToken function down through Routes:
App.js
import "./App.css";
import React from "react";
import { Routes } from "../config";
import { useToken } from "../hooks";
import Login from "./Login";
const App = () => {
const { token, setToken } = useToken();
if (!token) {
return <Login setToken={setToken} />;
}
return <Routes setToken={setToken} />;
};
export default App;
Routes.js
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Login, Home } from "../../pages";
const Routes = ({ setToken }) => {
return (
<Router>
<Switch>
<Route path="/login">
<Login setToken={setToken} />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
};
export default Routes;
<Route path="/login">
<Login /> /* <--- this line is calling Login component but is passing setToken as undefined */
</Route>

How to pass user name to react page?

I have this react code.
Apps.js
// react-router-auth
import React, {useState} from "react";
import { BrowserRouter as Router, Link, Route } from "react-router-dom";
import PrivateRoute from './PrivateRoute';
import Home from './pages/Home';
import Admin from './pages/Admin';
import Login from "./pages/Login";
import Signup from "./pages/Signup";
import { AuthContext } from "./context/auth";
function App(props) {
const [authTokens, setAuthTokens] = useState();
const setTokens = (data) => {
localStorage.setItem("tokens", JSON.stringify(data));
setAuthTokens(data);
}
return (
<AuthContext.Provider value={{ authTokens, setAuthTokens: setTokens }}>
<Router>
<div>
<ul>
<li>
<Link to="/">Home Page</Link>
</li>
<li>
<Link to={{ pathname: "/admin", state:{username: props.location}}}>Admin Page</Link>
</li>
<li>
<Link to={{ pathname: "/login", state:{referer: props.location}}}>Login Page</Link>
</li>
<li>
<Link to={{ pathname: "/signup", state:{referer: props.location}}}>Sign Up Page</Link>
</li>
</ul>
<p>
stuff
</p>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<PrivateRoute path="/admin" component={Admin} />
</div>
</Router>
</AuthContext.Provider>);
}
export default App;
Login.js
import React, { useState } from "react";
import { Link, Redirect } from 'react-router-dom';
import axios from 'axios';
import logoImg from "../img/logo.svg";
import { Card, Logo, Form, Input, Button, Error } from '../components/AuthForms';
import { useAuth } from "../context/auth";
function Login(props) {
const [isLoggedIn, setLoggedIn] = useState(false);
const [isError, setIsError] = useState(false);
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
const { setAuthTokens } = useAuth();
const referer = props.location.state.referer || '/';
function postLogin() {
console.log('postLogin called.');
const something = axios.post('http://127.0.0.1:8000/rest-auth/login/', {"username" : userName, "password": password} ).then(
result => {
console.log('postLogin called. username is ' + userName);
if( result.status === 200 ) {
setAuthTokens(result.data);
setLoggedIn(true);
setUserName(userName=> userName);
} else {
setIsError(true);
}
}).catch(e=>{setIsError(true);}
);
console.log('postLogin end. something is :');
console.log(something);
} // end postLogin
if (isLoggedIn) {
console.log('postLogin isLoggedIn is true and referer is ' + referer);
return <Redirect to={referer} />;
}
return (
<Card>
<Logo src={logoImg} />
<Form>
<Input
type="username"
value={userName}
onChange={e=>{
setUserName(e.target.value);
}}
placeholder="username"
/>
<Input
type="password"
value={password}
onChange={e=>{
setPassword(e.target.value);
}}
placeholder="password"
/>
<Button onClick={postLogin}>Sign In</Button>
</Form>
<Link to="/signup">Don't have an account?</Link>
{ isError&& <Error>The username or password provider were incorrect.</Error>}
</Card>
);
}
export default Login;
Admin.js
import React, { useState } from "react";
import { Button } from "../components/AuthForms"
import {useAuth} from "../context/auth";
function Admin(props) {
const { setAuthTokens } = useAuth();
const [userName, setUserName] = useState();
function logOut () {
setAuthTokens();
}
return (
<div>
<div>Admin Page userName is [{props.username}]</div>
<div>Admin Page userName is [{userName}]</div>
<Button onClick={logOut}>Log out</Button>
</div>);
}
export default Admin;
When I login I do not see the userName.
What a I doing wrong?
Update: I also have this file, auth.js
import { createContext, useContext } from 'react';
export const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
The problem is that you're not passing the property username to the Admin page. The property is being set in Login page and its not assigned to the context or the Admin page.
One of the easiest ways of setting a logged in Username is setting it in localstorage and retrieving it in the pages you need. This is obviously very exploitable and not recommended for sensitive data.
The other workaround is using React's Context APIs. In your AuthContext you can use useState(username, setUsername) = (window.localStorage.getItem('username') || '') and pass it down as props. You can retrieve the setUsername function in the login page and update it in the admin page.
export const AuthContext = createContext();
const AuthContextProvider = (props) => {
const [username, setUsername] = useState(null);
return (
<AuthContext.Provider
value={{
data: username,
updateUserName: (value) => {
setUsername(value)
}
}}>
{props.children}
</AuthContext.Provider>
);
};

Categories