i am trying save user object in context but i am gettin g undefined
this is my context:
import { createContext } from "react";
export const UserContext = createContext(null)
this is routs :
import { UserContext } from './contexts/UserContext.js';
const [user, setUser] = useState();
<UserContext.Provider value={{user:user , setUser:setUser}}>
<Routes>
<Route path="/login" exact element={ <Login />} />
<Route path="/numberinput" exact element={<NumberInput />} />
<Route path="/VerifyPhone" exact element={<VerifyPhone />} />
<Route path="/Register" exact element={<Register />} />
<Route path="/ChangePassword" exact element={<ChangePassword />} />
<Route path="/" exact element={<PrivateRoute><Home /></PrivateRoute>} />
{/* <Route path="/Answers" exact element={<Answers />} />
<Route path="/results/:id/:quizzes_id" exact element={<Results />} /> */}
<Route path="/payment" element={<PrivateRoute><Payment /></PrivateRoute>} />
<Route path="/*" element={<FourOFour />} />
</Routes>
</UserContext.Provider>
and this is how i want to store data in another file:
import { UserContext } from '../../contexts/UserContext.js';
const { setUser } = useContext(UserContext);
baseUrl
.post('api/v1/login', data)
.then((response) => {
setUser(response.data.data);
console.log(response.data.data);
Swal.fire({
icon: 'success',
title: response.data.data.message,
showConfirmButton: false,
timer: 1000,
}).then(() => {
window.location.pathname = '/';
});
})
and when i log the user in '/' rout i am getting undefiend
You should initialize properties of the context in first parameter of the createContext function as follows,
const userContext = createContext({ user: null, setUser: () => {} })
You forgot to add an initial value to the useState hook.
const [user, setUser] = useState(null);
And,
Don't use only a console.log() to log the user as it runs only once when your App mounts.
Do this instead to log the user every time it changes:
// state
const [user, setUser] = useState(null);
// log user every time it changes
useEffect(()=> {
console.log(user, "user from effect hook")
}, [user])
Set user in Login component
import React from "react";
// import UserContext correctly
import { UserContext } from "<path-to-UserContext>";
export default function Login() {
const { user, setUser } = useContext(UserContext);
// set the user
useEffect(() => {
setUser("something");
}, []);
return <></>;
}
Note: I'm assuming that you are getting the data from API correctly.
Related
I am trying to send users to different routes based on the roles of the user which is stored in the realtime firebase database, but I am getting the following error:
App.js:36 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'users')
Following is my App.js file where I am making the call for the firebase data"
App.js
`
import React from "react";
import { Route, Routes, Navigate } from "react-router-dom";
import Landing from "./components/Landing";
import PhoneDetails from "./components/PhoneDetails";
import Home from "./components/Home/App.jsx";
import Signup from "./components/Signup";
import SignIn from "./components/Signin";
import { auth } from "./firebase-config.js";
import { useEffect } from "react";
import FirebaseData from "./firebaseData";
function App() {
document.body.style = "background: #F8F5FA;";
// getting the user data from firebase
const firebaseData = FirebaseData();
const [displayName, setDisplayName] = React.useState("");
const [isAuthenticated, setIsAuthenticated] = React.useState(false);
const [role, setRole] = React.useState("");
useEffect(() => {
auth.onAuthStateChanged((user) => {
if (user) {
// User is signed in
// ...
setIsAuthenticated(trEue);
setDisplayName(user.displayName);
// ERROR ON THIS LINE
setRole(firebaseData.users[user.uid].role)
// setRole(firebaseData.users[user.uid].role);
} else {
// User is signed out
// ...
setIsAuthenticated(false);
setDisplayName("");
setRole("");
}
});
}, []);
console.log("role:", role);
return (
<Routes>
<Route
path="/"
exact
element={
<Home isAuthenticated={isAuthenticated} displayName={displayName} role={role}/>
}
/>
<Route path="/signup" element={<Signup />} />
<Route path="/signin" element={<SignIn />} />
{
isAuthenticated && role === "admin" ? (
<Route path="/home" element={<Landing />} />
) : (
<Route
path="/"
element={
<Home isAuthenticated={isAuthenticated} displayName={displayName} />
}
/>
)
}
{isAuthenticated && role === "admin" ? (
<Route path="/details" element={<PhoneDetails />} />
) : (
<Route
path="/"
element={
<Home isAuthenticated={isAuthenticated} displayName={displayName} />
}
/>
)}
<Route path="/" element={<Navigate replace to="/" />} />
<Route path="*" element={<Navigate replace to="/" />} />
</Routes>
);
}
export default App;
`
In my App.js I am calling the FirebaseData() file which is given below:
firebaseData.js
`
import {database} from "./firebase-config";
import React from "react";
import {ref, onValue} from "firebase/database";
import {useEffect} from "react";
const db = database;
export default function FirebaseData() {
const [data, setData] = React.useState(null);
useEffect(() => {
onValue(ref(db), (snapshot) => {
setData(snapshot.val());
});
}, []);
return data;
}
`
The data in the firebase DB is stored in the following format:
users
---->uid
------>roles
I've tried to find the solution for this but couldn't find any. Any help will be appreciated!
check firebaseData is defined in the useEffect and check if users exists using ? operator
useEffect(() => {
if(firebaseData){
auth.onAuthStateChanged((user) => {
if (user) {
// User is signed in
// ...
setIsAuthenticated(trEue);
setDisplayName(user.displayName);
// ERROR ON THIS LINE
setRole(firebaseData.users?.[user.uid]?.role)
// setRole(firebaseData.users[user.uid].role);
} else {
// User is signed out
// ...
setIsAuthenticated(false);
setDisplayName("");
setRole("");
}
});
}
}, [firebaseData]);
Hello i need help with my app.
What sense is to put my User data to useContext if when i refresh page all data disapear?
How to make this context permament?
I have been sitting with this all day, and when i try to get data in HomePage, everything is ok until i refresh page.
The second question is about JWT. It's used only on server side, right? It's verifing the token when I'm making server reqest only?
below is my code
App.js
import Navbar from "./components/Navbar";
import AddNewAnnoucement from "./components/pages/AddNewAnnoucement/AddNewAnnoucement";
import { Route, Routes } from 'react-router-dom';
import Home from "./components/pages/Home";
import Annoucements from "./components/pages/Annoucements/Annoucements";
import Register from "./components/pages/Register/Register";
import Login from "./components/pages/Login/Login";
import { useState, useMemo, useEffect, createContext } from "react";
import { getProfile, tokenIsValid } from './service/userService.js'
export const UserContext = createContext();
function App() {
const [userData, setUserData] = useState({
token: undefined,
user: undefined,
})
useEffect(() => {
const isLoggedIn = async () => {
let token = localStorage.getItem("token")
if (token == null) {
localStorage.setItem("token", "")
token = ""
}
const tokenResponse = tokenIsValid(token);
tokenResponse.then((res) => {
if (res.data) {
const userResponse = getProfile(token);
userResponse.then((res) => {
setUserData({
token: token,
data: res.data
})
})
}
}).catch((err) => {
console.log(err);
}
)
}
isLoggedIn();
}, [])
return <>
<UserContext.Provider value={{ userData, setUserData }}>
<Navbar />
<div className='container'>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/annoucements' element={<Annoucements />} />
<Route path='/annoucements/add' element={<AddNewAnnoucement />} />
<Route path='/register' element={<Register />} />
<Route path='/login' element={<Login />} />
</Routes>
</div>
</UserContext.Provider>
</>
}
export default App;
I have a react component index.js that fetches the user information from a Laravel server through a fetch call. The information is provided to the context UserContext, which is declared in a separate file and imported, near the top-level of the app as follows.
UserContext.jsx
import { createContext } from "react";
const UserContext = createContext(null);
export default UserContext;
const [user, setUser] = useState(null);
useEffect(() => {
// Get logged in user
fetch('/user', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
}).then(res => res.json()).then(data => {
setUser(data);
}).catch(err => {
setUser(null)
});
}
return (
<UserContext.Provider value={user}>
<Header/>
<main>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home categories={categories} />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/profile/:id" element={<Profile />} />
<Route path="/profile/:id/edit" element={<EditProfile />} />
<Route path="/profile/:id/registrations" element={<MyRegistrations />} />
<Route path="/posts" element={<Posts />}></Route>
<Route path="/posts/:id" element={<Post categories={categories} />}></Route>
<Route path="/category/:id" element={<Posts />} />
<Route path="/403" element={<Error error={403} />} />
<Route path="/404" element={<Error error={404} />} />
<Route path="/500" element={<Error error={500} />} />
<Route path="*" element={<Error error={404} />} />
</Routes>
</BrowserRouter>
</main>
<Footer/>
</UserContext.Provider>
);
When I try to access user in <Header>, it works as expected. However, in the routes nested in the react-router-dom <Routes>, it returns null.
Header.jsx, Post.jsx declaration to access user
const user = useContext(UserContext);
I suspected that this could be caused because of the context provided by react-router-dom or the nesting, so I tried to pull <Post/> to the top level and disable react-router-dom but it seems to be the same issue.
Post.jsx
import { useState, useEffect, useContext } from 'react';
import React from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import * as DOMPurify from 'dompurify';
import { Container } from 'react-bootstrap';
import UserContext from '../context/userContext';
export default function Post({ categories }) {
const user = React.useContext(UserContext);
let navigate = useNavigate();
let params = useParams();
const [id, setId] = useState(params.id);
const [post, setPost] = useState(null);
const [registered, setRegistered] = useState(false);
const inCourse = (id, courses) => {
console.log(id, courses);
return courses.filter(course => course.id == id).length > 0;
}
const inEvent = (id, events) => {
return events.filter(event => event.id == id).length > 0;
}
useEffect(() => {
{/* fetch post from api, works correctly */}
}, [id]);
useEffect(() => {
}, [user, id]);
return (
{/* unnecessary jsx */}
);
}
This question already has an answer here:
React-Router-Dom unable to render page but routes back due to PrivateRoute
(1 answer)
Closed 8 months ago.
My problem is that the moment i navigate to the homepage and the user is not authenticated the page shows for a split second and then move on to the login page. I want it to redirect to login only and not show the homepage for a split second
I already created a private route in my project but for a split second the protected routes shows when i navigate on to it.
here is my code:
AuthContextProvider
const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
return () => unsubscribe();
}, []);
const value = { user };
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
PrivateRoute.js
const PrivateRoute = ({ children }) => {
let { user } = useAuth();
if (user) {
return <Outlet />;
} else {
return <Navigate to="/login" />;
}
};
App.js
function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={<Layout />}>
<Route element={<PrivateRoute />}>
<Route path="/" element={<Home />} />
<Route path="/home" element={<Home />} />
<Route path="/reminders" element={<Reminders />} />
<Route path="/archive" element={<Archive />} />
<Route path="/trash" element={<Trash />} />
</Route>
</Route>
</Routes>
);
}
Loginpage.js
const LoginPage = () => {
const { user } = useAuth();
const navigate = useNavigate();
const signIn = async () => {
const provider = new GoogleAuthProvider();
await signInWithRedirect(auth, provider);
};
useEffect(() => {
onAuthStateChanged(auth, (currentUser) => {
if (currentUser) {
navigate("/");
}
});
}, []);
return (
<>
<button
onClick={signIn}
className="bg-blue-500 p-3 text-white hover:bg-blue-600"
>
Sign In With Google
</button>
</>
);
};
Code for hindering the Loggedin User to go to the Login Route
I have created a SpecialRoute which will redirect the loggedIn User to the mainpage if the user tries to go the login page.
SpecialRoute.js
import { Login } from '../pages/Login';
import { useAuth } from '../firebase-config';
import React from 'react';
import { Outlet, Navigate } from 'react-router-dom';
// import { useAuth } from '../firebase-config';
export const SpecialRoute = () => {
const user = useAuth();
return user ? <Outlet /> : <Navigate to="/" replace />;
};
App.js
<Route element={<SpecialRoute />}>
<Route path="/login" element={<Login />} />
</Route>
In your Private Route Component, do this :-
const PrivateRoute = ({ children }) => {
let { user } = useAuth();
return typeof user === 'undefined' ? (
<h1>Loading.....</h1>
) : user ? (
<Outlet />
) : (
<Navigate to="/login" />
);
};
Below is how I created my private routes (in Firebase v9):-
useAuth Hook
// custom hook
export function useAuth() {
//
const [currentUser, setCurrentUser] = useState<any>();
useEffect(() => {
const unSubscribe = onAuthStateChanged(auth, (user) =>
setCurrentUser(user)
);
return unSubscribe;
}, []);
return currentUser;
}
My PrivateRoute/ProtectedRouted Component
import { Login } from '../pages/Login';
import React from 'react';
import { Outlet } from 'react-router-dom';
import { useAuth } from '../firebase-config';
export const ProtectedRoute = () => {
const user = useAuth();
console.log('/////user autheticated', user);
return typeof user === 'undefined' ? (
<h1>Loading.....</h1>
) : user ? (
<Outlet />
) : (
<Login />
);
};
App.js
function App() {
return (
<>
<Router>
<Routes>
<Route element={<ProtectedRoute />}>
<Route path="/" element={<Home />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signin />} />
</Routes>
</Router>
</>
);
}
The problem I'm running into is that currentUser in App.js is null when <PrivateRoute /> renders, which will cause it to render a <Redirect /> and navigate to /login.
However, if I view the React Dev Tools I can see that the value field in Context.Provider does correctly have a user object set.This prop should rerender the rest of the app but it does not.
Why doesn't currentUser updating update the routes?
Auth.js
import React, { useEffect, useState } from 'react';
import firebase from 'firebase';
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged(setCurrentUser);
}, []);
return (
<AuthContext.Provider value={{ currentUser }}>
{children}
</AuthContext.Provider>
);
};
App.js
import { AuthProvider } from './Auth';
import { AuthContext } from './Auth';
function App() {
const PrivateRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useContext(AuthContext);
return (
<Route
{...rest}
render={props =>
currentUser ? (
<Component {...props} {...rest} />
) : (
<Redirect to={{ pathname: '/login' }} />
)
}
/>
);
};
return (
<AuthProvider>
<Router history={createBrowserHistory()}>
<Switch>
<PrivateRoute path="/" exact component={HomeScreen} />
<Route path="/login" exact component={LogIn} />
</Switch>
</Router>
</AuthProvider>
);
}