Accessing Properties of Linked Objects in ListView RenderRow function throws undefined error
See original GitHub issueLong winded version is a question on SO, but I am quite certain this is a bug as described in detail farther down this report.
Goal
In the renderRow function to be given as a prop to ListView:
renderRow(item) {
return (
<Text>{item.department.name}</Text>
);
}
Where department is an object property of item
Expected Results
In a row of the ListView, a string of the name property belonging to the department linked to item.
Actual Results
Red Screen of Death Quite a bit of scroll to that screen, can upload more screen captures of it or someone can tell me how to output it to console or a text file.
Steps & Code to Reproduce
You can check out the question on stackoverflow, it was iterated on and has a bit of the flow to it. Below is a more succinct summary of where I believe the bug lays with a basic/partial setup to replicate.
Code Sample
I’ll briefly touch where I think the problem is. This code sample creates console logs that can be seen withadb logcat ReactNative:V ReactNativeJS:V
// Schema Example
class Item {};
Item.schema = {
name: 'Item',
primaryKey: 'id',
properties: {
id: 'string',
name: 'string',
department: 'ItemDepartment',
}
}
class ItemDepartment {};
ItemDepartment.schema = {
name: 'ItemDepartment',
primaryKey: 'id',
properties: {
id: 'string',
name: 'string',
parentDepartment: 'ItemDepartment'
}
}
// This truthy test in the if statement allows item.department.name work as intended!
// Check the console log below for a possible lead as for why
getItemDepartmentName(item) {
let code = item.code;
console.log("item: " + item)
console.log("code: " + code)
console.log("typeofX: " + typeof code)
if (code) {
console.log("code True: true")
return item.department.name
}
console.log("code True: false");
return "Undefined"
}
renderRow(item) {
return(
<Text>{this.getItemDepartmentName(item)}</Text>
)
}
// for this to work you must bind this on renderRow in listView:
<ListView
...
renderRow={this.renderRow.bind(this)}
.../>
Now, for the console output (Trimmed for readability):
ReactNativeJS: item: function (row1, row2) {return row1!==row2;}
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item: function defaultGetRowData(dataBlob, sectionID, rowID) {
ReactNativeJS: return dataBlob[sectionID][rowID];}
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item: function () {return false;}
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item: function defaultGetSectionHeaderData(dataBlob, sectionID) {
ReactNativeJS: return dataBlob[sectionID];}
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item:
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item:
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item:
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item:
ReactNativeJS: code: undefined
ReactNativeJS: typeofX: undefined
ReactNativeJS: code True: false
ReactNativeJS: item: [object RealmObject]
ReactNativeJS: code: MI1
ReactNativeJS: typeofX: string
ReactNativeJS: code True: true
ReactNativeJS: item: [object RealmObject]
ReactNativeJS: code: MI2
ReactNativeJS: typeofX: string
ReactNativeJS: code True: true
ReactNativeJS: item: [object RealmObject]
ReactNativeJS: code: MI3
ReactNativeJS: typeofX: string
ReactNativeJS: code True: true
So for some reason (could be my code, but it seems to be hooked up as it should be, pretty standard datasource etc.), ListView starts off calling renderRow with a whole lot of weird inputs, starting with the datasource rowHasChanged function, then what I assume are the Realm.ListView.DataSource default functions. Following that a bunch of calls with what appears to be no argument which obviously has undefined variables. After that it behaves totally normally!
Obviously, if you call item.department.name or the equivalent with any other realm database within the renderRow function, you are gonna to get an error pertaining to undefined. This is due to the strange calling of renderRow with inputs that are not RealmObjects at the start.
Now the weirdest thing about this all is that this doesn’t seem to be a problem with any other properties of the item object: item.name, item.code, even item.department works, successfully returning a RealmObject. As soon as you try to query item.department.name shit hits the fan. I don’t have a hypothesis on that yet. I have my little truthy/falsy fix as above and intend to get on with my work!
Version of Realm and tooling
Realm version(s): 0.11
Android Studio version: Atom/Nuclide latest
Which Android version and device: Only tested on genymotion simulating a nexus 9
Issue Analytics
- State:
- Created 7 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
@Chris-Petty Thanks for posting this! I noticed from this code that the
dataSource
is being passed into itself here:dataSource.cloneWithRows(dataSource)
. This could explain why you’re seeing its own methods being passed intorenderRow
. Let me know if that helps!Glad to hear it worked! It’s because the items being passed into
renderRow
were still objects (functions), soitem.code
would be undefined but wouldn’t throw an error. However,item.department.name
would be trying to access a property on something undefined (item.department
).