问题
I'm trying to access the properties of a linked object through the parent object, but I only get back undefined. This is code within the renderRow method/prop of ListView (I am using the Realm ListView). On android, haven't tested iOS. Getting the linked object itself seems to work fine. Heres some (trimmed) code context:
// Schemas being used to create realm (trimmed down to relevant)
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'
}
}
// renderRow method (trimmed but same error thrown)
renderRow(item) {
return (
<Text>{item.department.name}</Text>
);
}
Poking around the realm shows me that both objects appear correctly instantiated with all properties.
I can access each Item string and number properties fine (i.e. item.name).
Trying item.department returns a RealmObject, assumedly the one that is linked.
item.department.name throws the error "undefined is not an object (evaluating 'item.department.name')"
This works fine outside of renderRow.
The long path of poking around has lead me to think the issue lies within this console.log from within renderRow:
renderRow(item) {
console.log('item.name: ' + item.name)
console.log('item.department: ' + item.department)
return (
<Text>{item.name}</Text>
);
}
The result:
ReactNativeJS: Running application “undisclosed” with appParams: {"initialProps":{},"rootTag":1}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF
ReactNativeJS: item.name:
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: defaultGetRowData
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name:
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: defaultGetSectionHeaderData
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: undefined
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: undefined
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: undefined
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: undefined
ReactNativeJS: item.department: undefined
ReactNativeJS: item.name: MockItem1
ReactNativeJS: item.department: [object RealmObject]
ReactNativeJS: item.name: MockItem2
ReactNativeJS: item.department: [object RealmObject]
ReactNativeJS: item.name: MockItem3
ReactNativeJS: item.department: [object RealmObject]
Interestingly enough the ListView works fine despite renderRow being called several times with nothing and undefined. As soon as I attempt item.department.name though:
Red Screen of death - undefined is not an object
Any feedback and suggestions would be appreciated! Is this a bug with Realm RN ListView or is this working as intended, but my implementation is wrong?
UPDATE: Got a dirty work around for now:
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)}
.../>
Basically just checking if the code property of item is truthy or not. Skips the first renderRows. Kept the log lines in for science, shows why this fix works/the bug if you watch in console with
adb logcat ReactNative:V ReactNativeJS:V
Tidied 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
...
回答1:
So the following is the constructor that was being used in the project. Don't put your dataSource into your dataSource. Otherwise ListView will call renderRow with properties of the DataSource Object as arguments, leading to all the odd behaviour in the original question.
constructor(props) {
super(props);
let dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
dataSource: dataSource.cloneWithRows(dataSource), // Bad
items: realm.objects('Item').sorted('name'),
};
this.componentDidMount = this.componentDidMount.bind(this);
}
componentDidMount() {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.state.items),
});
}
Set state of dataSource with data instead:
...
let data = realm.objects('Item').sorted('name')
this.state = {
dataSource: dataSource.cloneWithRows(data),
items: data,
};
...
Turns out my dataSource setup wasn't quite standard!
回答2:
By looking at your question and logs, it looks like an Item does not always have a department.
Trying item.department returns a RealmObject, assumedly the one that is linked. item.department.name throws the error "undefined is not an object (evaluating 'item.department.name')"
So my guess you have some code that isn't checking if item.department is present first before trying to access item.department.name. If item.department is undefined, then the error message you're getting would make sense. Please let me know if that helps, or if I misunderstood something!
来源:https://stackoverflow.com/questions/36539381/linked-objects-properties-in-realm-react-native-listview-return-undefined-erro