Next.js - Cannot read properties of undefined (reading 'user') - javascript

I use Next.js and Next-auth for my project.
I'm building a Sidebar component where I want to show a list of items from a user.
So I'm getting the session with useSession.
When I log the session like so...
export default function Sidebar() {
const { data: session, status } = useSession();
console.log(session);
return (
...
)
}
...I get an object including the user object.
But when I try to log the user like so...
export default function Sidebar() {
const { data: session, status } = useSession();
console.log(session.user);
return (
...
)
}
I get this error:
TypeError: Cannot read properties of undefined (reading 'user')
Any idea what's the problem here?
Thanks a lot,
Gabriel

As useSession is a hook, it will make data available asynchronously. Hence, you need to check if session is not undefined before logging it/ using it.
console.log(session?.user);
or
if(session) {
console.log(session.user);
}

The problem may be in the deconstruction of the object.
And it's recommended you check if it's not null, just like Rameez said.
Try this:
const { data, status } = useSession();
if(data.session.user){
console.log(data.session.user);
}
return (
...
);

Related

props are returned as string instead of object

I'm currently implementing user authentication on my website, and I'm trying to restrict access to the login and signup pages if the user is logged in. To do so, I am implementing this getServerSideProps to redirect the user if they're logged in:
export async function getServerSideProps(context) {
if (context.req.cookies.user) {
return {
redirect: {
destination: '/',
permanent: true,
},
}
}
return {}
}
If I return an empty object ({}), next gives me this error:
Reason: Props must be returned as a plain object from getServerSideProps: `{ props: { ... } }` (received: `[object Array]`).
If instead of returning {}, I return
{
props: {}
}
the code works all right. Does anyone know why this is happening?
I'm using a custom _app.jsx file.
In the documentation, it's clearly mentioned that the props argument is optional:
This is actually intended. If you were using TypeScript, return {} would have thrown you error as GetServerSidePropsResult is defined like this here:
export type GetServerSidePropsResult<P> =
| { props: P | Promise<P> }
| { redirect: Redirect }
| { notFound: true }
It means that any one of props, redirect, notFound needs to be present in the returned object. Perhaps you can create an issue at their GitHub (and maybe a PR) to fix the documentation.
As mentioned by #tromgy, it was just the documentation that is unclear.

Vuex Getter Undefined

I am new to Vue.js and experiencing an issue with Vuex modules and Axios. I have a "post" component that retrieves a slug from the router and fetches data with Axios which is then retrieved with Vuex Getters.
I am able to retrieve data successfully but then I still see this error on my DevTools, "TypeError: Cannot read property 'name' of undefined"
Due to this error I am not able to pass this.post.name to Vue-Meta.
Codes
Post.vue
computed: {
...mapGetters(["post"]),
},
mounted() {
const slug = this.$route.params.slug;
this.fetchPost({ slug: slug });
},
methods: {
...mapActions(["fetchPost"]),
/store/modules/post.js
const state = {
post: [],
};
const getters = {
post: (state) => {
return post;
}
};
const actions = {
async fetchPost({ commit }, arg) {
try {
await axios.get("/post/" + arg.slug).then((response) => {
commit("setPost", response.data);
});
} catch (error) {
console.log(error);
}
},
};
const mutations = {
setPost: (state, post) => (state.post = post),
};
export default {
state,
getters,
actions,
mutations,
};
Your getter is utterly wrong: a state getter is supposed to be a function that takes in the entire state as a param and retrieves whatever you're interested in from it. Your version...
const getters = {
post: (state) => {
return post;
}
};
...takes in the state as a param but doesn't use it. Instead, it returns a variable (post) which has not been defined in that context.
Which will always return undefined, regardless of current value of state.post.
And, as you already know, JavaScript can't access property 'name' of undefined.
To get the current value of state.post, use:
const getters = {
post: state => state.post
}
Or
const getters = {
post: (state) => { return state.post; }
}
... if you fancy brackets.
Also, out of principle, I suggest initializing your post with an empty object {} instead of an empty array [].
Changing variable types as few times as possible is a very good coding habit, providing huge benefits in the long run.
Edit (after [mcve])
You have a bigger problem: the import from your axios plugin returns undefined. So you can't call get on it. Because you wrapped that call into a try/catch block, you don't get to see the error but the endpoint is never called.
I don't know where you picked that plugin syntax from but it's clearly not exporting axios. Replacing the import with import axios from 'axios' works as expected.
Another advice would be to namespace your store module. That's going to become useful when you'll have more than one module and you'll want to specifically reference a particular mutation/action on a specific module. You'll need to slightly change mapActions and mapGetters at that point.
See it working here.

JSON Object Property not returnable - "Cannot Read Property of Undefined"

Ok, so I'm building out a custom API in React. When I make the calls, I'm getting JSON data back and store that into local storage with JSON.Stringify:
localStorage.setItem('user', JSON.stringify(response.data))
Later, I call this item onto the Homepage to return some of that data once the user is logged in using:
var user = JSON.parse([localStorage.getItem('user')])
This returns the object:
{
"OrderId":0,
"IsLoggedIn":true,
"ModeOfSaleId":64,
"OriginalModeOfSaleId":64,
"SourceId":8580,
"LoginInfo":{"ConstituentId":190554,"OriginalConstituentId":190554,"UserId":"test#email.org","Status":"P","FailedAttempts":0,"LockedDate":null,"ElectronicAddress":"test#email.org"},
"CartInfo":{"PerformanceCount":0,"PackageCount":0,"ContributionCount":0,"MembershipCount":0,"UserDefinedFeeCount":0,"GiftCertificateCount":0,"PaymentCount":0,"FirstSeatAddedDateTime":null},
"BusinessFacing":false,
"IsGuest":false,
"CheckoutStatus":{"Status":"No Checkout","Date":null},
"HasLockedSeats":false,
"SeatsExpired":false
}
The Issue:
Un-nested properties return normally {user.OrderId} or {user.ModeOfSaleId} However, trying to return the nested values like {user.LoginInfo.ConstituentID} result in the error:
Uncaught TypeError: Cannot read property 'ConstituentId' of undefined
Returning {user.LoginInfo} actually returns an object, but obviously, can't print that to a string. Returning {user.LoginInfo["ConstituentId"]} results in the error:
Uncaught TypeError: Cannot read property 'ConstituentId' of undefined
So yeah, I'm stumped, I don't know how I'm returning this incorrectly. Any help is appreciated.
This code works for me:
localStorage.setItem("user", JSON.stringify({
"OrderId":0,
"IsLoggedIn":true,
"ModeOfSaleId":64,
"OriginalModeOfSaleId":64,
"SourceId":8580,
"LoginInfo":{"ConstituentId":190554,"OriginalConstituentId":190554,"UserId":"test#email.org","Status":"P","FailedAttempts":0,"LockedDate":null,"ElectronicAddress":"test#email.org"},
"CartInfo":{"PerformanceCount":0,"PackageCount":0,"ContributionCount":0,"MembershipCount":0,"UserDefinedFeeCount":0,"GiftCertificateCount":0,"PaymentCount":0,"FirstSeatAddedDateTime":null},
"BusinessFacing":false,
"IsGuest":false,
"CheckoutStatus":{"Status":"No Checkout","Date":null},
"HasLockedSeats":false,
"SeatsExpired":false
}));
const user = JSON.parse(localStorage.getItem("user"));
console.log(user.LoginInfo.OriginalConstituentId);
What about using spread operator to get what you want?
const user = JSON.parse(localStorage.getItem('user'))
const { ConstituentId, UserId } = user.LoginInfo
console.log(ConstituentId) // 190554
Ok, so the way I'm returning these values seems to be an "issue" because of the way React handles it's Render event. When I'm pulling in the data on the componentDidMount() event, a Render event still fires just before this.
componentDidMount() {
this.setState({
user: JSON.parse([localStorage.getItem('user')]),
users: { loading: true }
});
}
So in the Render event:
render() {
const { user, users, loading } = this.state;
var { ConstituentId, UserId } = user.LoginInfo
return (
<div className="col-md-6 col-md-offset-3">
<h1>Hi!</h1>
<p>{UserId}</p>
<p>You're logged in with React & Basic HTTP Authentication!!</p>
<h3>Users from secure api end point:</h3>
<p>
<Link to="/login">Logout</Link>
</p>
</div>
);
}
It fires TWICE, once BEFORE the state.user is set by componentDidMount() and once again after. So, my code was erroring out because of the first firing of Render, when nothing was set, hence the undefined message. I figured out how to bypass this with checking the login info object is returning as typeof object. This is in my render event:
var result = (typeof user.loginInfo === 'object');
if (result && loading) {
console.log(result)
console.log(user.LoginInfo.ConstituentId)
var { ConstituentId, UserId } = user.LoginInfo
}
But that's not very elegant. So, ultimately I re-wrote how I was handling unloaded information in componentDidMount() by creating a state prop called 'loading':
this.state = {
loading: true,
user: {}
};
In componentDidMount() I'm doing this:
this.setState({
user: JSON.parse(localStorage.getItem('user')),
loading: false
});
And in render():
const { loading, user } = this.state;
if (!loading) {
var { ConstituentId, UserId } = user.LoginInfo
}
console.log(ConstituentId)
It works great!
Basically, I'm just waiting for componentDidMount() to fire using the loading state by setting it to false in the function. Then we know it's loaded and can successfully render the data.

TypeError: Cannot read property 'classList' of undefined

I do a form Login to Study on React... and this error i can't resolve..
TypeError: Cannot read property 'classList' of undefined
My Code Error:
changeState(){
const {isLogginActive} = this.state;
if(isLogginActive) {
this.rightSide.classList.remove("right");
this.rightSide.classList.add("left");
} else {
this.rightSide.classList.remove("left");
this.rightSide.classList.add("right");
}
this.setState((prevState)=> ({ isLogginActive: !prevState.isLogginActive }));
}
Some one can help me... have a one solution for this ... doing in React.
Thanks.
I am assuming that rightSide is a property defined using the createRef API.
In that case, classList is only accessible through the current attribute of the ref.
this.rightSide.current.classList
As createRef() is asynchronous, it might return null if you are accessing it early, e.g. on the componentDidMount lifecycle.
Hence, it is always safer to add an if statement to check for current
changeState(){
const {isLogginActive} = this.state;
if (this.rightSide.current) {
if(isLogginActive) {
this.rightSide.current.classList.remove("right");
this.rightSide.current.classList.add("left");
} else {
this.rightSide.current.classList.remove("left");
this.rightSide.current.classList.add("right");
}
this.setState((prevState)=> ({ isLogginActive: !prevState.isLogginActive }));
}
}

Javascript, in a React application assign to {} in a function component, code review

I have this code in a friend of mine React application and I need to understand what this code does explicitly:
const Component = ()=> (
<QueryFetcher>
{({ data }) => {
const { user: { profile = {} } = {} } = data
return (
<div>
{profile.username && profile.username}
</div>
)
}}
</QueryFetcher>
)
What is this line for?
const { user: { profile = {} } = {} } = data
Is it correct to assign something to {} using { user: { profile = {} } = {} } in this functional component? Or in a render() hook of a stateful component in React?
const { user: { profile = {} } = {} } = data basically means that your retrieving the user profile.
const means that you are creating a new variable
{ user: { profile } } } means that you are retrieving profile inside of user
= {} means that if the object is undefined, use an empty object so it will not fail because doing user.profile will throw an error if user is undefined.
= data means that you retrieving this info from the data variable
So, this line means, from the variable data, go take the user, if the user is undefined, use an empty object. Then, go take the profile, if the profile is undefined, use an empty object. Then create a variable called profile with the result. This is like doing this:
const user = data.user === undefined ? {} : data.user;
const profile = user.profile === undefined ? {} : user.profile;
What is this line for?
const { user: { profile = {} } = {} } = data
It's basically just chained ES6 object-destructuring with default values.
What this line does in words:
Read "user" from "data", if "user" is undefined, assign {} as a default value
Read "profile" from "user", if "profile" is undefined, assign {} as a default value
Is it correct
It is mostly a short-hand syntax used to remove repetitive stuff. So instead of accessing multiple object props separately e.g.
this.props.prop1, this.props.prop2, ...
you can use
const { prop1, prop2 } = this.props;
It also helps other readers later quickly understanding what variables are used in a method if all necessary props are destructured at the start.

Categories

Resources