Linked objects' properties in Realm React-Native ListView return undefined (error: undefined is not an object)

本秂侑毒 提交于 2019-12-10 19:01:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!