I am trying to display user login info onto a React Material UI Typography label that is nested into an App bar(Header.js) by using data from another .js file(Login.js).
Here is the relevant code from the Header.js file:
<Typography color='textSecondary' className={classes.userText}>{}</Typography> // The label for the user info
and here is the data to be fetched from the Login.js file:
const [formData, updateFormData] = useState(initialFormData);
const handleChange = (e) => {
updateFormData({
...formData,
[e.target.name]: e.target.value.trim(),
});
};
const [error, setError] = useState();
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
axiosInstance
.post(`token/`, {
email: formData.email, //the data I want to be displayed on the App Bar
password: formData.password,
})
.then((res) => {
localStorage.setItem('access_token', res.data.access);
localStorage.setItem('refresh_token', res.data.refresh);
axiosInstance.defaults.headers['Authorization'] =
'JWT ' + localStorage.getItem('access_token');
history.push('/');
//console.log(res);
//console.log(res.data);
}, reason =>{
console.error(reason);
setError("Invalid login details!")
alert("Login Failed!\nIncorrect login details!");
});
};
I am expecting to see the user email and display it in the Typography label...
you have to pass data from one component to another, and you really have 2 options here(excluding props drilling).
either you pass data using React's ContextAPI, which is easier assuming you are a newbie, or you can use Redux. There is not much to go from your code so you have to read docs here
contextApi: https://refine.dev/blog/usecontext-and-react-context/
redux: https://redux.js.org/tutorials/fundamentals/part-5-ui-react
Related
I have created this Auth Component and it works fine. Except that, It does not redirect if the unauthenticated user tries to visit /dashboard.
The backend upon receiving /api/me request, knows the user by having the cookie. So I have (Cookie-Session) Authentication technique.
export const UserContext = createContext();
const Auth = ({ children }) => {
const [user, setUser] = useState(null);
const [gotUser, setGotUser] = useState(false);
const navigate = useNavigate();
const getUser = async () => {
const res = await fetch('/api/me');
const data = await res.json();
setUser(data);
if (user) {
setGotUser(true);
}
};
useEffect(() => {
if (!gotUser) {
getUser();
}
}, [user, gotUser, navigate]);
if (!user) {
navigate('/login');
}
console.log(user);
return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
};
So the main issue is that no redirection done. Also, The user passed to the context is not updated properly. Maybe because I am confused about what to use in useEffect .
Any help is appreciated.
Issues
There are a couple issues:
The "unauthenticated" state matches the "I don't know yet" state (i.e. the initial state value) and the component is redirecting too early. It should wait until the user state is confirmed.
The navigate function is called as an unintentional side-effect directly in the body of the component. Either move the navigate call into a useEffect hook or render the Navigate component to issue the imperative navigation action.
Solution
Use an undefined initial user state and explicitly check that prior to issuing navigation action or rendering the UserContext.Provider component.
const Auth = ({ children }) => {
const [user, setUser] = useState(); // <-- initially undefined
const navigate = useNavigate();
const getUser = async () => {
try {
const res = await fetch('/api/me');
const data = await res.json();
setUser(data); // <-- ensure defined, i.e. user object or null value
} catch (error) {
// handler error, set error state, etc...
setUser(null); // <-- set to null for no user
}
};
useEffect(() => {
if (user === undefined) {
getUser();
}
}, [user]);
if (user === undefined) {
return null; // <-- or loading indicator, spinner, etc
}
// No either redirect to log user in or render context provider and app
return user
? <Navigate to="/login" replace />
: <UserContext.Provider value={user}>{children}</UserContext.Provider>;
};
useEffect runs after your JSX is rendered, so as your code is made, on a page refresh this if (!user) that calls navigate('/login') will always pass, as before the useEffect does its work, user is null, that inital value you gave to useState. Yet it's not redirecting because navigate does not work inside JSX, it should be replaced with Navigate the component.
Also, in getUser, you have this if (user) juste after setUser(data), that wouldn't work well as user won't get updated immediately, as updating a state is an asynchronous task which takes effect after a re-redner .
To fix your problems you can add a checking state, return some loader while the user is being verified. Also you can optimise a little bit your code overall, like getting ride of that gotUser state:
export const UserContext = createContext();
const Auth = ({ children }) => {
const [user, setUser] = useState(null);
const [checking, setChecking] = useState(true);
const getUser = async () => {
try {
const res = await fetch("/api/me");
const data = await res.json();
setUser(data);
} catch (error) {
setUser(null);
} finally {
setChecking(false);
}
};
useEffect(() => {
if (!user) {
getUser();
}
}, [user]);
if (checking) {
return <p>Checking...</p>;
}
if (!user) {
return <Navigate to="/login" replace />
}
return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
};
export default Auth;
I am relatively new to javascript and React and I am helping out with a project. I want to create a profile page for a signed in user with information stored in a firebase real time database. But the component is not rendering and the console shows 'Uncaught TypeError: Cannot read properties of null (reading 'username')'. I surmise it is because the data from the database is not being fetched before rendering. The data exists. The profile hook -
import React, { useEffect,useState } from 'react';
import {useAuth} from '../contexts/AuthContext'
import { getDatabase,ref, onValue} from "firebase/database";
function Profile(){
const [userData, setUserData] = useState({});
const currentUser = useAuth();
useEffect(()=>{ putData()
},[])
async function putData(){
let db = getDatabase();
let refd = ref(db,'users/'+ currentUser.currentUser.uid );
onValue(refd, (snapshot) => {
console.log(snapshot.val());
setUserData(snapshot.val());
},
(errorObject) => {
console.log('The read failed: ' + errorObject.name);
})
}
return(
<div>
<h3>Username : {userData.username}</h3>
<h3>Institute name : {userData.institute_name}</h3>
<h3>Accomodation : {userData.accomodation}</h3>
<h3>Phone no. : {userData.phone}</h3>
<h3>Email : {userData.email}</h3>
</div>
);
}
export default Profile;
Does the problem lie with the 'onValue' part or with the react part? Firebase documentation is not helping with my current understanding. Any help on how to accomplish this is appreciated.
useEffect(() => {
try {
//getting previously saved data
// console.log({ SelectedCaseDetails });
const getData = async () => {
const docRef = doc(
db,
"here comes your path to your document"
);
const docSnap = await getDoc(docRef);
console.log("data -->", docSnap.data());
if (docSnap.exists()) {
setData(docSnap.data());
setData(() => ({ ...docSnap.data() }));
}
};
getData();
} catch (error) {
console.log({ error });
}
}, []);
You just have to run your get data function in useEffect that runs when page is loading
Hope this helps 🤗
¯\(ツ)/¯
I have a FormBody.js component with the help of which I create a form and submit the details to my backend server made using express.js. Following is the code snippet:
const [postData, setPostData] = useState({
author: "",
message: "",
imageFile: ""
})
const handleSubmit = (event) => {
event.preventDefault();
console.log(postData);
createPost(postData);
clear();
}
This is working perfectly fine but when I want to get all of my posts from mongodb to my another component which is PostsBody.js, I don't have anything to keep track of "postData" state as mentioned above in the code snippet as it was in other component (FormBody.js). So right now, I have to reload the React app every time in order to see new posts.
This is inside PostsBody.js component:
const [posts, setPosts] = useState([]);
useEffect(() => {
const getData = async () => {
const allPosts = await getAllPosts();
setPosts(allPosts);
}
getData();
}, []);
So I need to pass [postData] inside this dependency array of useEffect in order to keep track of changes, How can I do that?
I am having an issue with useQuery from #apollo/client
I have a Navbar component
const Navbar = () => {
const { loading, data, error } = useQuery(GET_CURRENT_USER);
console.log('navbar', data)
return <ReactStuff />
}
And I also have a UserProfile component which allows the user to logout via a button. When the user presses the button, this code is ran:
const {
getCurrentUser,
changePassword,
changePasswordData,
logoutUser,
} = useUsers();
const logout = () => {
logoutUser();
localStorage.removeItem("authToken");
props.history.push("/");
};
useUsers is a custom hook which houses the resetStore function:
const useUser = () => {
const { client, loading, error, data, refetch } = useQuery(GET_CURRENT_USER);
const logoutUser = () => {
console.log("firing logout user");
client
.resetStore()
.then((data) => {
console.log("here in reset store success");
})
.catch((err) => {
console.log("here in error");
}); // causes uncaught error when logging out.
};
return {
// other useUser functions
logoutUser
}
}
Now I can't for the life of me figure out why the Navbar component, does not get updated when logout is pressed.
I have a withAuth higher-order component which does the exact same query, and this works absolutely fine. The user is sent to the /login page, and If I was to console.log(data) it is updated as undefined - as expected.
import { GET_CURRENT_USER } from "../graphql/queries/user";
/**
* Using this HOC
* we can check to see if the user is authed
*/
const withAuth = (Component) => (props) => {
const history = useHistory();
const { loading, data, error } = useQuery(GET_CURRENT_USER);
if (error) console.warn(error);
if (loading) return null;
if (data && data.user) {
return <Component {...props} />;
}
if (!data) {
history.push("/login");
return "null";
}
return null;
};
For some reason, this useQuery inside Navbar is holding onto this stale data for some reason and I can't figure out how to make it work correctly.
Update 1:
I've changed the logoutUser function to use clearStore() and the same thing happens, the Navbar is not updated, but I am redirected to /login and withAuth is working as intended.
const logoutUser = () => {
client
.clearStore()
.then((data) => console.log(data)) // logs []
.catch((err) => console.log(err)); // no error because no refetch
};
You're not waiting for the store to reset, probably the redirection and storage clean up happen before the reset completes, try doing that once it has finished
const logout = () => {
logoutUser(() => {
localStorage.removeItem('authToken');
props.history.push('/');
});
};
const logoutUser = onLogout => {
console.log('firing logout user');
client
.resetStore()
.then(data => {
onLogout();
})
.catch(err => {
console.log('here in error');
}); // causes uncaught error when logging out.
};
Check: do you have only ONE ApolloClient instance?
In some cases, if you configuring ApolloClient in the custom class or file you can implicitly create multiple apolloClient instances, for example by 'import' statement. In that case you clearing only one of the caches you made.
Hello everyone i am new on React Native and i am trying to display some data i am fetching from firebase
Here is the data Json Shema i want to fetch
For now i just wrote a redux action creator like this
export const employeesFetch = () =>{
const {currentUser} = firebase.auth();
return(dispatch) => {
firebase.database().ref(`/users/${currentUser.uid}/employees`)
.on('value', snap => {
dispatch({type: EMPLOYEES_FETCH_SUCCESS, payload: snap.val()});
})
};
};
Here a screen Capture of my console :
Now how can i have access to each employee of each user and display each properties of them ?
Thanks you for your help ..