Reactjs state update after localstorage data changes - javascript

I have the user inside localstorage, when user logouts the localstorage data becomes NULL. When user logins, the localstorages fills with user's data but to check this my userEffect in App.js do not reflect any change.
i have signUp
dispatch(signin(form, history));
history.push("/"); //go back to App.js file
in Navbar the user data changes
const Navbar = (props) => {
const [user, setUser] = useState(JSON.parse(localStorage.getItem("profile")));
const logout = () => {
dispatch({ type: "LOGOUT" });
dispatch({
type: "EMPTY_CART",
});
history.push("/");
setUser(null);
};
now at App.js i have
const user = JSON.parse(localStorage?.getItem("profile"));
const getCartItems = useCallback(async () => {
if (user) {
console.log("Yes user exixts");
dispatch(getEachUserCart(user?.result?._id));
} else {
console.log("No user exist");
}
}, []); //
useEffect(() => {
getCartItems();
}, [getCartItems]);
Now if u look above, after dispatching signUp action, i come back to App.js but here the useEffect don't run nor it checks if user have changed.

Hey – looks like you have a missing dependency issue. You need to have it like so
const getCartItems = useCallback(async () => {
if (user) {
console.log("Yes user exixts");
dispatch(getEachUserCart(user?.result?._id));
} else {
console.log("No user exist");
}
}, [user]);
Otherwise, this function will never be redeclared with the latest user value. Kindly let me know if that helps

Related

Why I have to refresh my app to show the right screen to the logged in user?

I have multiple users in my app, and I can login smoothly but when I logout and I login as second user I still can see the first user screens until I refresh my app then I can see the second user screen?
Here is my code:
const UserInbox = () => {
const [userData, setUserData] = useState([])
const message = db.collection('feedback').where('recipient','==',userData ?
auth.currentUser.email:'unknown')
{/*fetch only logged in user messages from database*/}
const fetchData = async()=>{
const unsubscribe = auth.onAuthStateChanged(async user => {
const list = [];
if(user){
await message
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const {userId,recipient,messageText} = doc.data()
list.push({
id:doc.id,
userId,
recipient,
messageText
})
// doc.data() is never undefined for query doc snapshots
console.log(doc.data().messageText);
});
setUserData(list)
})
} else{
setUserData(null)
}
})
return () => unsubscribe();
}
I was trying to fix it but I couldn't figure it out because when I look at my code I don't see any errors but I feel I'm missing something? so please do anyone can help me out to display the right screen for the right logged in without refreshing the app with every single login.

Embed a logged user id to a form

I use the next for the login of my application. When you successfuly login you're redirected to a dashboard with a Form.
async function loginUser(e) {
e.preventDefault()
await Axios.post("http://localhost:3005/users/login", {
email,
password
}).then((response) => {
if (!response.data.auth){
setSession(null)
} else{
setSession(response.data.token, response.data.user)
}
});
};
export const getUser = () =>{
const user = sessionStorage.getItem("user");
if(user) return JSON.parse(user);
else return null;
}
export const getToken = () => {
return sessionStorage.getItem("token") || null
}
export const setSession = (token, user) => {
sessionStorage.setItem("token", token)
sessionStorage.setItem("user", JSON.stringify(user))
}
export const removeSession = () => {
sessionStorage.removeItem("token")
sessionStorage.removeItem("user")
}
In that dashboard the user can fill the next form. This works good, the forms are posted and the user get to see all the forms that he posted.
I want the user to be able to share the form link with his id embedded to it so whenever someone fill the form you can associate it with the user who shared it.
My problem is that whenever someone tries to fill the form it wont post as the person isnt logged in and form cant get an user id, and even if the person was logged it would pass his id and not the one of the person who shared the form.
const Form = () => {
const user = getUser();
const [firstName, setFirstName] = useState();
const [middleName, setMiddleName] = useState();
const [surname, setSurname] = useState();
const [secondSurname, setSecondSurname] = useState();
const [email, setEmail] = useState();
const [contactNumber, setContactNumber] = useState();
const createForm = () => {
Axios.post("http://localhost:3005/forms", {
firstName,
middleName,
surname,
secondSurname,
email,
contactNumber,
ownerUser: user._id
}).then((response) => {
alert("Form sent");
});
};`
Any help on how to embed the user._id is deeply thanked!
Yeah, I wouldn't think there's a way to embed it just sharing the form's link with no further reference. You could generate some sort of other usable ID that you can add to the specific form's URL, if you don't want to use the user's ID directly. And associate that one to the user ID in the back-end. Then finally grab it through the form's page through dynamic variable.
Example:
website.com/form/:id
And using props.match.params.id with Router, or your decided strategy.
Edits: Minor wording
Okay so here is what I did, i created 2 components; one form for the logged user he can fill it normally and it has a button that redirect to a form that is intendeed to be shared:
So logged user form looks like this:
const Form = () => {
const user = getUser();
const own = user._id;
const navigate = useNavigate();
const nav = (own) => {
navigate(`/form/${own}`)
}
/// states, axios and the form
<button onClick={createForm}>Send</button>
<button onClick={() => nav(own)} >Go to</button>
Then in the form to be shared I used useMatch from react router dom in the next way to retrieve the user id:
import { useMatch } from "react-router-dom";
const SharedForm = () => {
const params = useMatch(`/form/:own`)
/// console.dir(params)
const owner = params.params.own
On this way the logged user id is embedded to the form and anyone with the link can fill it.

Add username on createUserWithEmailAndPassword in Firebase with React

I want to add the username on the signup of the user and I am using the following code:
//Create Account With Email&Password
const createUser = (email, password, username) => {
return createUserWithEmailAndPassword(auth, email, password).then(() => {
updateProfile(auth.currentUser, {
displayName: username,
});
});
};
This is my useEffect in the same js file
useEffect(() => {
console.log('useEffect');
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
return () => unsubscribe();
}, []);
This code is adding the displayname successfully, but when I redirect to my account page the displayname is not directly showing up and I am getting a memory leak warning from the router-dom. Is there a cleaner and better way to do this?
I believe it's because the account page loads before firebase loads the auth data, you can use something like
onAuthStateChanged(auth,(user)=>{
if(user){
getUserName = auth.currentUser.displayName;
// Load the rest of the page
}
}
at your redirected user page,assuming you are using the right auth state, which you can refer from here https://firebase.google.com/docs/auth/web/auth-state-persistence?authuser=0

call api and render data after states get updated

In use effect I am checking current role of user, if it is admin setAdmin(true) set the state of admin. The default admin state is false. When component gets rendered, it gets rendered with admin as false and state gets updated in sometime. I want to call api and render data after state gets updated.
useEffect(async () => {
//Authenticates User through their email
let firebaseId;
const user = await firebase.auth().currentUser;
if (user) {
let getUserProfile = async () => {
let loggedInUser = await axios.get(
`${config.API_URL}/data/profile/${user.uid}`
);
if (loggedInUser.data.role == "admin") {
setAdmin(true);
}
};
getUserProfile();
}
}, []);
You can use useEffect hook in above case.
Ex:
useEffect(() => {
// Call your API
}, [admin]);
Above hook will call when admin state updated.

Next/Apollo: How to correctly update apollo cache if the relevant query was run in getInitialProps

I'm using nextjs and apollo (with react hooks). I am trying to update the user object in the apollo cache (I don't want to refetch). What is happening is that the user seems to be getting updated in the cache just fine but the user object that the component uses is not getting updated. Here is the relevant code:
The page:
// pages/index.js
...
const Page = ({ user }) => {
return <MyPage user={user} />;
};
Page.getInitialProps = async (context) => {
const { apolloClient } = context;
const user = await apolloClient.query({ query: GetUser }).then(({ data: { user } }) => user);
return { user };
};
export default Page;
And the component:
// components/MyPage.jsx
...
export default ({ user }) => {
const [toggleActive] = useMutation(ToggleActive, {
variables: { id: user.id },
update: proxy => {
const currentData = proxy.readQuery({ query: GetUser });
if (!currentData || !currentData.user) {
return;
}
console.log('user active in update:', currentData.user.isActive);
proxy.writeQuery({
query: GetUser,
data: {
...currentData,
user: {
...currentData.user,
isActive: !currentData.user.isActive
}
}
});
}
});
console.log('user active status:', user.isActive);
return <button onClick={toggleActive}>Toggle active</button>;
};
When I continuously press the button, the console log in the update function shows the user active status as flipping back and forth, so it seems that the apollo cache is getting updated properly. However, the console log in the component always shows the same status value.
I don't see this problem happening with any other apollo cache updates that I'm doing where the data object that the component uses is acquired in the component using the useQuery hook (i.e. not from a query in getInitialProps).

Categories

Resources