redux state value returns undefined - javascript

I declare state via redux connect
const mapStateToProps = state => ({
singleBase: state.interaction.base
});
export default requiresLogin()(connect(mapStateToProps)(BasePage));
The state shows fine via console log console.log(this.props.singleBase);
id: "5b757e6743904228586a5a7f"
creatorId: "5b6e39ce08406602d0a9e125"
title: "tester"
currentUsers: 2
messages: 0
On the backend I have the following model:
const BaseSchema = mongoose.Schema({
creatorId: { type: mongoose.Schema.Types.ObjectId, required: true },
title: { type: String, required: true },
currentUsers: { type: Number, default: 0 },
messages: { type: Number, default: 0 }
});
But when I try to console log the value of currentUsers: console.log(this.props.singleBase.currentUsers); I get the following error: Cannot read property 'currentUsers' of undefined.
I tried both setting the Schema to a pure number, e.g. 5, as well as as a text "5". Neither one works. What detail am I missing to be able to get the value of currentUsers ?
EDIT & SOLUTION:
const users =
this.props.singleBase && this.props.singleBase.currentUsers !== undefined
? this.props.singleBase.currentUsers
: 0;
return (
<div>
<h2>{users}</h2>
</div>
);
Here we ensure that this.props.singleBase exists and is true, while I make sure that this.props.singleBase.currentUsers has a value that is not undefined. If both evaluates true I display this.props.singleBase.currentUsers. The point of this is that until the asynchronous action has completed the singleBase will be empty. Once filled with data, I can display the currentUsers value.

You are most probably getting this data asynchronously, this is why you are getting this error. Before logging this.props.singleBase you should see an undefined in the console. This does not fire an error but if you try to get some property of an undefined object you hit this error. Trying to log undefined objects is ok, but trying to log a property where this object is undefined is not since at this time that object is undefined.
You can put a condition before your log:
this.props.singleBase && console.log(this.props.singleBase.currentUsers);
This is what will you do to render your items in the future instead of logging them. So, always remember, if you are doing an asynchronous job, there will be no data in the first render.

const users =
this.props.singleBase && this.props.singleBase.currentUsers !== undefined
? this.props.singleBase.currentUsers
: 0;
return (
<div>
<h2>{users}</h2>
</div>
);
Here we ensure that this.props.singleBase exists and is true, while I make sure that this.props.singleBase.currentUsers has a value that is not undefined. If both evaluates true I display this.props.singleBase.currentUsers. The point of this is that until the asynchronous action has completed the singleBase will be empty. Once filled with data, I can display the currentUsers value.

It might be happening because you're trying to console.log it before the current state is loaded. Try setting some flag like loading=true while you're getting your asynchronous data, and then change it to false after loading it.

Related

Prisma/React Query Dependent undefined type challenges

I would like to take the output of one query (a TRPC query on Prisma) and use this as the dependent input in a future query.
I followed the dependent documentation for React Query but running into type errors that the return of the first may possibly be undefined (e.g. product is possibly 'undefined'):
const { data: product } = api.product.getUnique.useQuery({ id: pid });
const options = api.option.getAll.useQuery(
{
product: product.productSize,
region: product.productRegion,
},
{ enabled: !!product }
);
Does the inclusion of enabled not already handle this? If not, what is the correct way to adapt for Typescript.
Just casting the product value as a boolean return any truthy value (f.e if product will be equal to {} it will still result in true, that means that product won't necessarily have the productSize or productRegion properties, I would change it first to:
{ enabled: !!product && product.productSize && product.productRegion }
If that doesn't fix the typescript error, you as a developer can know for sure that the values are actually there so what you can use the as keyword in typescript to tell it that you know for sure that the type is what you want it to be:
(In this example I assumed that the values are string but you can change it to number or whatever the true value of them are)
const options = api.option.getAll.useQuery(
{
product: product.productSize as string,
region: product.productRegion as string,
},
{ enabled: !!product && product.productSize && product.productRegion }
);

Cannot assign to read only property 'approved_by_customer_admin' of object '#<Object>' after updating the api data manually

I know that the same question has been asked before but none of them are working for me, so here is my requirement ->
I have users list and I logged in as a Admin, First I called getUsers api to get the list of the users and displayed the list in the UI, there is a button Accept for each user to approve them, So on click of Accept button, I am calling this method ->
const [allUserList, setAllUserList] = useState(usersArray)
const [filterUserListAfterUpdate, setFilterUserListAfterUpdate] = useState([])
const onClickAcceptUser (id) => {
let updatedUserList = []
allUserList.forEach(user => {
if(user._id === id){
user.approved_by_customer_admin = true
}
updatedUserList.push(user)
})
setFilterUserListAfterUpdate(updatedUserList)
}
return(<UserList filteredUsersList = {filterUserListAfterUpdate} onAccept={(id) => onClickAcceptUser(id) />)
NOTE -: I am using NodeJs as in backend and MongoDB and this is my full user object =>
//All the below values are dummy not real.
approved_by_customer_admin: false
auth0_id: "email|622e0414804c"
company_id: "622df44843fc4"
created_date: "2022-03-13T14:47:52.589Z"
email: "demo#gmail.com"
industry_name: "gmail"
is_active: false
phone_number: ""
prefer_contact: "email"
role: "customer_auditor"
updated_date: "2022-03-13T14:47:52.589Z"
__v: 0
_id: "6243ffa"
I need to change only one property of object(or maybe more than one, in future).
At the line user.approved_by_customer_admin = true I got the error in my console.
Any suggestions would be appreciable.
find an index of array of object and update the value of that like this
let updatedUserList = [...allUserList]
const objIndex = updatedUserList.findIndex(user => user._id == approveUser.id);
updatedUserList[objIndex].approved_by_customer_admin = true;
filterUserListAfterUpdate(updatedUserList)
Tapping in the dark: based in your comment in one of the answer mentioning "Cannot assign to read only property" I am suspecting some other component like Mongoose to produce the error.
Some search lead me to How to fix the error (TypeError: Cannot assign to read only property 'map' of object '#<QueryCursor>') and https://github.com/Automattic/mongoose/issues/11377, suggesting to downgrade Node (strictly below 17.5.0)

Why does a test for this.data.length fail?

In a Vue component I have a data() function that returns an object of data – standard stuff really:
data() {
return {
PlaceholderHTML: "",
ProductID: "",
CustomInvalidMessage: "",
Form: {
Price: "",
Currency: ""
},
}
},
When some data (usually a File) is posted to the server using axios, a ProductID is generated on the server and sent back to Vue. I then set the ProductID like
this.ProductID = response.data.ProductID;
All that works fine. In Vue Developer Tools the ProductID value is indeed set to 15005. If I do a console.log(ProductID) then I get back empty string on initial state and when ProductID is set after the axios.post() the console shows 15005.
So why does the following test never succeed?
const formData = new FormData();
if (this.ProductID != null && this.ProductID.length) {
formData.append("ProductID", this.ProductID); // This never happens
console.log(`Appended ${this.ProductID}`) // This too never prints anything
}
So if I remove the if(... && this.ProductID.length) part above, then there is no problem:
if (this.ProductID != null) {
formData.append("ProductID", this.ProductID); // Appended as empty string on initial state and then 15005 after this.ProductID is set
}
What is wrong with the && this.ProductID.length part?
this.ProductID is a number and in js the Number constructor does not have length method only String does so, to fix your problem check it like this:
this.ProductID.toString().length

ReactJS State OR Logical Operator always causing type error

I've got a simple state setup for a component that still throws the error: TypeError: Cannot read property 'year' of undefined with this code:
export default class Login extends Component {
state = {
isLoading: false,
events: this.props.events,
activeDate: {
year: this.props.events[0].year || "",
month: this.props.events[0].months[0].month || "",
}
};
//...
}
I'm having trouble understanding why this errors out instead of just setting the value to null. undefined should render the binary operation as false and default to "". Can anyone explain?
Instead of using year: this.props.events[0].year || "", I found that that this worked just as well, year: "" && this.props.events[0].year. The AND operator will equate to the last true value.
But, as #AlexanderStaroselsky pointed out, this isn't best practice. See this article for more details.
You can validate that the object in the array at position 0 is not null then use && before to access the property of the array object. Finally, add || to specify a default value when both conditions give null or undefined.
this.props.events[0] && this.props.events[0].year || ""

How to .update() value to NULL in sequelize

I'm writing my service to update a row using sequelize for PostGres. When I try out my query using a PSequel it works fine:
UPDATE "test_table" SET "test_col"=NULL WHERE "id"= '2'
But using sequelize it throws a 500 error:
db.TestTable.update({ testCol: NULL }, { where: { id: id } })
.then((count) => {
if (count) {
return count;
}
});
My model does allowNull which I believe is what allows null values to be the default as well as set:
testCol: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
field: 'test_col'
},
Any other value but NULL works as expected. Is there a different method for setting null values?
From the looks of it, I think your issue is that you are using SQL's syntax for a null value ('NULL') where you should be using JS syntax ('null').
db.TestTable.update({ testCol: null }, { where: { id: id } })
.then((count) => {
if (count) {
return count;
}
});
should work.
Have you checked a more detailed error message in logs? I'd suggest you to add a promise catching error and then update your question.
For now, my guess is that you created your connection with omitNull: true. Call an update function with just one null property probably is the reason of error 500 because it'll generate a incomplete UPDATE command (without SET).
Try to set omitNull: false or, if you cannot do this test, try to update this way:
db.TestTable.testCol = null;
db.TestTable.save(['testCol']);
More info here.

Categories