I have a const newProducts
that is returning undefined
and yet says it isn't undefined in the chrome dev console:
It says it is defined in the yellow highlighted text in the console, and undefined when hovering over it. It shouldn't be undefined. I have stepped through the code and the returns
inside the map
are returning values. Why is this const
coming up undefined
and also not undefined
?
searchResults.reducer.js
// @flow
import initialState from '../../config/config'
import {
FETCH_PRODUCTS_REJECTED,
UPDATE_SEARCH_RESULTS
} from '../search-page/searchPage.action'
import { SET_SELECTED_SHOP } from '../search-results/searchResults.action'
const searchResults = (
initialResultsState: [] = initialState.get('searchResults'),
action: Object): string => {
switch (action.type) {
case UPDATE_SEARCH_RESULTS: {
const newProducts = action.payload.products.map(product => {
return {
shop: {
id: product.shop[0].f1,
name: product.shop[0].f2,
coordinate: {
latitude: product.shop[0].f4,
longitude: product.shop[0].f3
},
selected: false
},
products: product.products
}
})
return initialResultsState.set('products', newProducts)
}
case SET_SELECTED_SHOP: {
const newProducts = initialResultsState.get('products').map(product => {
if (product.shop.id === action.payload) {
return {
shop: {
...product.shop,
selected: true
},
products: product.products
}
} else {
return {
shop: {
...product.shop,
selected: false
},
products: product.products
}
}
})
return initialResultsState.set('products', newProducts)
}
case FETCH_PRODUCTS_REJECTED: {
console.log('there was an issue getting products: ',
action.payload)
return initialResultsState
}
default:
return initialResultsState
}
}
export default searchResults
I think it's a side effect of what transpilation does with const
, as after transpilation the JS runtime actually has to track 2 different variables.
React Native uses Babel to transpile (source, pointing at line in 0.45.1 where it enables block scoping).
You define a constant with same name several times in different blocks, it's OK in ES2015 as constants are block-scoped, but this concept does not exist in ES5, so such constants are transpiled to variables with different names.
For example, consider this ES2015 snippet:
const i = Date.now() % 2;
switch(i) {
case 0: {
const x = "zero";
console.log("x", x);
}
case 1: {
const x = "one";
console.log("x", x);
}
default: {
const x = "wat";
console.log("x", x);
}
}
With Babel, it gets transpiled (← see it in action) to:
"use strict";
var i = Date.now() % 2;
switch (i) {
case 0:
{
var x = "zero";
console.log("x", x);
}
case 1:
{
var _x = "one";
console.log("x", _x);
}
default:
{
var _x2 = "wat";
console.log("x", _x2);
}
}
So in this example the JS runtime actually has 3 different variables to represent x
.
So you might be looking at a line with foo
, which your browser shows via a source map, but in "reality" what the browser is looking at might be _foo2
, so depending on a lot of things (transpilation settings, source map generation, Chrome version, rest of the code, where exactly you are in the call stack...), Chrome dev tools might have trouble to track this and decide which of foo
or _foo
or _foo2
it should pick when you look at foo
.
Example with ES2015 transpiled to ES5 and source map:
(behavior is slightly different, as it depends on a lot of parameters, but it shows the issue with transpiling of constants with identical names -- in another test, with different transpiling + sourcemapping parameters, I managed to get something similar to your situation)
Suggestion
(I expect the following to be very obvious to O.P., but could be useful to leave in the answer)
With const
semantics, you have 2 different constants with the same name, in 2 different blocks. In my opinion it's useful to define a constant (or variable using let
instead of var
) with a block scope, in order to avoid surprises with var
scoping (scoped to the nearest parent function), but defining variables or constants with the same name in 2 neighboring blocks is calling for confusion (transpiled or not).
It would make better sense to decide whether or not those 2 symbols represent the same thing or not (up to you), and then:
if so, use let
to define them as a single variable for the parent scope.
if not, keep them as const
but with 2 different names. Code will be clearer, and after transpilation, debugging information shown by dev tools should be more useful.