如何在Realm数据更改时更新React Native ListView

时间:2016-05-30 15:17:31

标签: react-native realm

我有一个存储在Realm DB中的'Activity'对象列表,它们显示在ListView上。 最初加载数据并在屏幕上显示数据没有问题。但是,当数据更新时(在另一个屏幕中,我们称之为'详细编辑屏幕')并且用户返回列表屏幕,列表不会更新。

我尝试在render方法中设置setState,但是返回一个空白屏幕。

    var activities = realm.objects('Activity').sorted('date');
    let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 
    ...
    module.exports = React.createClass({
      getInitialState: function(){
        return { 
          dataSource: ds.cloneWithRows(activities),
        };
      },
    ...
    render: function(){
       //update the list of activities
        activities = realm.objects('Activity').sorted('date'); 
        this.setState({dataSource: ds.cloneWithRows(activities)});
         return ( 
          <View>
              {(!activities || activities.length<1) && noActivitiesMessage}
                  <ListView style={styles.listStyle} dataSource={this.state.dataSource} 
            renderRow={this._renderRow} />
    </View>

)
...
}

4 个答案:

答案 0 :(得分:4)

我遇到了和你一样的问题。我的问题是使用Realm ListView解决的。我像这样使用它

import { ListView } from 'realm/react-native';

class List extends Component {

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    src = realm.objects('MyObject');
    this.setState({
      dataSource:this.state.dataSource.cloneWithRows(src),
      data:src
    });
  } 

  updateData(){
   // update or add object in Realm
   this.setState({
     dataSource:this.state.dataSource.cloneWithRows(this.state.data)
   });
  } 

  render(){
    return( 
        <ListView
          dataSource={this.state.dataSource}
          renderRow=... />
  }
}

答案 1 :(得分:3)

我建议在NPM上使用react-native-realm包(完全披露,我是作者,所以我有点偏颇)。它使用提供者模式(类似于react-redux),通过简单地将它们包装在connectRealm高阶组件中,为组件提供领域数据和自动更改事件监听(以及自动删除这些事件监听器)。定义哪些模式以及在组件的道具中将它们映射到何处。

你可以像这样使用它。在应用的顶级组件中,使用RealmProvider包装子组件。

// App.js

// the file you use to wire up your realm schemas, etc.
import realm from './path/to/your/realm/file';
import { RealmProvider } from 'react-native-realm';
import List from './List';

class App extends React.Component {

  render() {
    <RealmProvider realm={realm}>
      <List />
    </RealmProvider>
  }

export default App;

然后在您的子组件中,如果他们需要领域数据,请使用connectRealm函数挂钩该数据。

// List.js

import { ListView } from 'realm/react-native';
import { connectRealm } from 'react-native-realm';

class List extends Component {

  constructor(props) {
    super(props);
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (r1, r2) => r1 !== r2,
      }).cloneWithRows(props.activities);
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(nextProps.activities),
    });
  } 

  render(){
    return ( 
      <ListView
        dataSource={this.state.dataSource}
        renderRow=... 
      />
    )
  }
}

export default connectRealm(List, {
  schemas: ['Activity'],
  mapToProps({ activities }) {
    return {
      activities: activities.sorted('date'), // do extra filtering and sorting here
    };
  },
})

答案 2 :(得分:1)

正如您在评论中已经提到的,可能无法在渲染函数中调用setState(它基本上会导致无限递归)。

这里最简单的解决方案是在构造函数中添加一个侦听器,对于您的示例,它将如下所示:

realm.addListener('change', () => {
    this.setState({dataSource: realm.objects('Activity').sorted('date'); })
});

答案 3 :(得分:0)

这是我的方法,感谢@ Johannes的回答以及@ tiby使用领域列表视图的建议。

constructor (props) {
    super(props)

    this.state = {
      ds: new ListView.DataSource({
        rowHasChanged (a, b) {
          return a.done !== b.done || a.text !== b.text || a.items || b.items
        }
      }),
      src: realm.objects(‘Object’),
    }

    realm.addListener('change', () => {
        this.setState({src: realm.objects(‘Object’) })
    });
}

render () {
    var dataSource = this.state.ds.cloneWithRows(this.state.src)
    return (
        <ListView
          dataSource={dataSource}
          …
        />
   )
}