Dima K.
Dima K.

Reputation: 1

Undefined object property whenever I loop through it

I'm trying to loop over an Object that I pass in from the Parent component but its properties return undefined.

I understand the first thing to check would be that the Object is actually not empty, but when I print it in the same useEffect below, it contains all of the data and information that I need. It's only when I loop through it and try to access the individual keys or properties that it is undefined

const [selectedCategory, setSelectedCategory] = useState < string[] > ([]);
useEffect(() => {
    console.log(salesTaxData) // This returns the correct existing data
    if (salesTaxData !== undefined) {
        Object.keys(salesTaxData).map(item => {
            if (salesTaxData[item].internalCode !== undefined)
                console.log(salesTaxData[item]
                .internalCode) // This keeps returning undefined even when the first console log above clearly indicates it does have a value
        })
    }
}, [salesTaxData]);

EDIT: Extra information:

console.log of the problem This image shows how the original object looks. It shows that both gstHst and pst keys are populated, but when I try to loop over them, they're empty. I also tried the suggestions in the replies below doing it with the for (const x in x) way and the JSON method to console log, but neither method fixed me issue.

Not sure what I'm doing wrong?

Thank you!

Upvotes: 0

Views: 832

Answers (1)

ProfDFrancis
ProfDFrancis

Reputation: 9411

Beware console.log in asynchronous code

What is displayed in the console may not be the value at the time of that console.log was executed, but rather the value at the time you are viewing it. This is a peculiar behaviour of browsers. I think it is intended to be helpful, but I personally find it annoying.

You would be better to reword your console.log as follows:

const [selectedCategory, setSelectedCategory] = useState < string[] > ([]);
useEffect(() => {
  console.log("salesTaxData:",JSON.stringify(salesTaxData, null, 2)) 
  if (salesTaxData !== undefined) {
    Object.keys(salesTaxData).map(item => {
        if (salesTaxData[item].internalCode !== undefined)
            console.log("salesTaxData[item].internalCode:",JSON.stringify(salesTaxData[item]
            .internalCode,null,2) 
    })
  }
}, [salesTaxData]);

Use JSON.stringify to force conversion into a string immediately

By doing this, even if the value of salesTaxData changes later, what is displayed on screen will not change, because it has already been stringified.

The ,null,2 just adds some tidy formatting to the output.

Paste the resulting console.log output as text, not an image

This means it is

(a) searchable

(b) copiable

(c) more quickly viewable

And therefore more likely to get your question answered.

Incidentally if you are not processing an array to return a new array, use .forEach rather than .map

.map is generally used when you are processing an array to make another array, with each element in the first array being mapped to a new element in the second array. e.g.

const doubled = values.map(x=>2*x)

When we see the .map function we are usually expecting what is inside to it to have no side effects, but rather simply return a new value.

If we are in fact intending to have side effects, we usually signal this to future readers, by using the .forEach function:

values.forEach(x=>{console.log(x, " times two is ", x*2})

What I am saying is that your line:

    Object.keys(salesTaxData).map(item => {

would be easier for future programmers to understand if written:

    Object.keys(salesTaxData).forEach(item => {

Upvotes: 1

Related Questions