【问题标题】:How to update React Native ListView when Realm data changes当 Realm 数据发生变化时如何更新 React Native ListView
【发布时间】:2016-05-30 15:17:30
【问题描述】:

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

我尝试在渲染方法中设置状态,但返回一个空白屏幕。

    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>

)
...
}

【问题讨论】:

  • 你是使用 Realm 的 ListView 还是 React Native 核心?
  • 我都试过了。如果我尝试更新 render() 中的状态,如上所示,使用 Realm 的 ListView 会使应用程序崩溃。它显示错误:在现有状态转换期间无法更新(例如在render 或其他组件的构造函数中)。渲染方法应该是 props 和 state 的纯函数;构造函数副作用是一种反模式,但可以移动到componentWillMount

标签: react-native realm


【解决方案1】:

我和你有同样的问题。我的问题是通过使用 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=... />
  }
}

【讨论】:

  • 当我单击列表项时,我的应用程序会打开一个新屏幕(表单),然后我通过道具将 updateData 传递给此表单。当我验证它调用 this.prop.updateData(data) 的表单时,我在领域中更新我的数据并执行 setState。抱歉,我没有在之前的示例中添加它。
【解决方案2】:

我建议在 NPM 上使用 react-native-realm 包(完全公开,我是作者,所以我有点偏见)。它使用提供者模式(类似于 react-redux)为您的组件提供领域数据和自动更改事件侦听(以及自动删除这些事件侦听器),只需将它们包装在 connectRealm 高阶组件中并定义哪个架构以及在组件的 props 中映射它们的位置。

你可以这样使用它。在您应用的顶级组件中,使用 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
    };
  },
})

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 非常感谢;整整一周都在敲我的头,试图跟踪我的领域变化
    【解决方案4】:

    感谢@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}
              …
            />
       )
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 2017-09-28
      • 2016-01-30
      • 2016-10-26
      • 1970-01-01
      相关资源
      最近更新 更多