I'm new to react, and I'm working on my biggest project yet, which is an online store. How original of me, I know.
I've created a context classes for the information I wish to pass on to other components:
import React from "react";
const AuthContext = React.createContext(
{
isLoggedIn: false,
isLoggedInEditVal: ()=>{},
currentLoggedUserId: "",
edit_currentLoggedUserId: ()=> {},
}
);
export default AuthContext;
and
import React from "react";
const usersAndProductsContext = React.createContext(
{
usersVal: [],
productsVal: [],
toggle_pressed_login_flag: () => {},
handleAddUser: () => {}
}
);
export default usersAndProductsContext;
In my App component, I wrap with both usersAndProductsContext.Provider and AuthContext.Provider, and pass in both of them the data I wish to share with my other components:
return (
<div className="App">
<usersAndProductsContext.Provider value={{
usersVal: usersVal,
productsVal: productsVal,
toggle_pressed_login_flag: toggle_pressed_login_flag,
handleAddUser: handleAddUser
}}>
<AuthContext.Provider
value={{
isLoggedIn: false,
currentUserId: "",
edit_currentLoggedUserId: edit_currentLoggedUserId,
currentLoggedUserId: currentLoggedUserId,
}}>
<Routes>
<Route exact path="/" element={<Login />}/>
<Route exact path="farmers" element={<Farmers />}/>
<Route exact path="customer" element={<Customer />}/>
<Route exact path="register" element={<Register />}/>
{/* <Route exact path="log in" element={<Login usersVal={usersVal}/>}/> */}
</Routes>
</AuthContext.Provider>
</usersAndProductsContext.Provider>
</div>
);
}
After making a login, I wish to redirect myself to another component at that point, while saving data.
My attempt doing it with useNavigate:
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import logo_img from "../Images/logo.png";
import { useNavigate } from 'react-router-dom';
import { useState, useContext } from 'react';
import { Paper } from '@material-ui/core';
import ErrorPopup from '../Components/ErrorPopup';
import AuthContext from '../Contexts/isLoggedIn-context';
import usersAndProductsContext from '../Contexts/usersAndProducts-context';
function Copyright(props) {
return (
<Typography variant="body2" color="text.secondary" align="center" {...props}>
{'Copyright © '}
<Link color="inherit" href="http://localhost:3000">
iFarm
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const theme = createTheme();
export default function Login() {
let [is_wrongLoginFlag, edit_is_wrongLoginFlag] = useState(false);
// let [loggedinVal, edit_loggedinVal] = useState(false);
let navigate = useNavigate();
//retrieve info from CONTEXES
const authCtx = useContext(AuthContext);
const usersAndItemsCtx = useContext(usersAndProductsContext)
//our user array
const usersVal = usersAndItemsCtx.usersVal
// console.log("first" usersVal[0].firstname)
React.useEffect(()=> {
{is_wrongLoginFlag ? setTimeout(()=>edit_is_wrongLoginFlag(false), 1000) : <></> }
}, [is_wrongLoginFlag])
//after inserting email and password, verify their existence.
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
let res = usersVal.find(user => user.email === data.get('email'));
if (res != undefined && res.password === data.get('password')) {
usersAndItemsCtx.toggle_pressed_login_flag(true); // need to verify this one..
setTimeout(()=>{authCtx.edit_currentLoggedUserId(res.id)}, 1000)
console.log("in login" authCtx.currentLoggedUserId)
// this email exists, progress to verifying pw.
navigate('/farmers'); // as a logged in user
// return (<></>)
}
else {
edit_is_wrongLoginFlag(true);
}
};
return (
<ThemeProvider theme={theme}>
<Container component="main" maxWidth="xs">
<Paper sx={{ background: "linear-gradient(to right, #5433ff, #20bdff, #a5fecb)" }}>
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Welcome back
</Typography>
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
// onClick={handleVerifyUserLogin}
sx={{ mt: 3, mb: 2 }}
>
Sign In
</Button>
{is_wrongLoginFlag ? <ErrorPopup message={"wrong email or password (maybe even both)"}/> : <></> }
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="/register" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</Paper>
</Container>
</ThemeProvider>
);
}
It seems like after I do the login and I'm being redirected to the 'farmers' page, I seem to lose my access to the context which was passed from my App.
Any ideas on how to sort such an issue?
If any further information is required, I would happily supply it.
Regards!
CodePudding user response:
you didn't change the state of "isLoggedIn" attribute on the AuthContext, "isLoggedIn" is always "false".
authCtx.isLoggedIn = true;
Add this line of code on the "Login" component after a successful login. It is also very recommended to use an AuthGuard to protect your routes that requires authentication.
Good luck with your project.
CodePudding user response:
It is recommended by react-router to use redirect
in these scenario but we can leave it at that for now. For navigate, it's almost like you reload the whole page at a different url and a reload of application will wipe out any data that you have in context. Because you don't have way to store this data, you lost it. The fact that you can access /farmers
is because you don't have an guard to check if user is authenticated to prevent users from accessing that page. Below are the possible solution which you can choose from:
- You can pass that context data into options.state as the second parameter of navigate (you can take a look at this to see where state is) and in your farmers page, you can take this info out and use it through
useEffect
and state. - Store the data in a storage space in the browser (cookie, localstorage, etc.) in your context file you can load these values into your context and consume and modify it whenever you modify the context.
I'd prefer the second approach to this issue since you can store everything in a centralized place and you don't have to worry about it's not being passed from one route to another.