【问题标题】:How to Render Realm ListView with Sections Header如何使用 Sections Header 渲染 Realm ListView
【发布时间】:2017-08-05 20:05:21
【问题描述】:

我将 react native 与领域 db 一起使用。领域架构如下:

  static schema = {
    name: 'TodoItem',
    primaryKey: 'id',
    properties: {
      id: {type: 'string'},
      value: {type: 'string'},
      Category: {type: 'string'},
      completed: {type: 'bool', default: false},
      createdTimestamp: {type: 'date'}
    }
  }

export const todoItemDS = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2, sectionHeaderHasChanged: (s1, s2) => s1 !== s2})

const mapStateToProps = (state, props) => ({
  dataSource: todoItemDS.cloneWithRowsAndSections(todoItemsResults),
}

ListView标签如下:

<ListView
          dataSource={dataSource}
          renderRow={this.renderRow.bind(this)}
          renderSectionHeader={this.renderSectionHeader.bind(this)}
        />

和renderSectionHeader:

renderSectionHeader(sectionData, category) {
  return (
    <Text>{category}</Text>
  )
}

renderRow(item){
  const {dataSource, deleteTodoItem} = this.props
  return (
    <View style={{ justifyContent: 'space-between',flexDirection: 'row'}}>
      <CheckBox onPress={(e) => this.completed(item.id,item.value,e.target.checked)} style={{marginTop: 15 }}checked={item.completed} />
      <Text onPress={(e) => this.goToPageTwo(item.id)} style={{ alignSelf: 'center',flex:10}} >{item.value}
      </Text>
      <Button iconLeft large transparent primary style={{ height: 30 , flex:1 }} onPress={() => deleteTodoItem(item)}>
          <Icon name="trash-o" style={{ color: 'red' }} />
      </Button>
  </View>) 
}

我从这个函数填充 todoItems 数据源:

export const getTodoItems = () => {

  const todoItems = TodoItem.get().sorted('createdTimestamp', true);
  return todoItems
}

但是,如图所示,行和部分使用空部分文本和空行文本呈现。

此代码中缺少什么以及如何正确呈现节和行?


我向填充数据源的领域代码添加了一个侦听器,如下所示:

export const getTodoItems = () => {
  console.log('create db:', Realm.path)
  const itemData = {}
  const todoItems = TodoItem.get().sorted('createdTimestamp', true).filtered('completed=false');
  todoItems.addListener((items, changes) => {
  // Update UI in response to inserted objects
  changes.insertions.forEach((index) => {
    if(itemData[items[index].Category]) {
      itemData[items[index].Category].push(items[index])
    } else
      itemData[items[index].Category] = []//;
    });

  // Update UI in response to modified objects
  changes.modifications.forEach((index) => {

  });

  // Update UI in response to deleted objects
  changes.deletions.forEach((index) => {
    // Deleted objects cannot be accessed directly
    // Support for accessing deleted objects coming soon...

  });

});;

  todoItems.forEach((item) => {
    if(itemData[item.Category]) {
      itemData[item.Category].push(item)
    } else
      itemData[item.Category] = []//;
    }) 
  return itemData //todoItems
}

但是,我看不到添加的项目。添加的项目仅在添加另一个项目后显示。有什么想法吗?

【问题讨论】:

  • 你能告诉我们你是如何生成todoItemsResults的吗?
  • @dotcomXY 我添加了填充数据源的函数。
  • 所以你可以看到相同数量的行和正确数量的类别行被渲染,只是那些 Text 组件中的内容是空的吗?
  • @dotcomXY 不。我为我看到的内容添加了一张图片。
  • 你能分享一下你的 renderRow 函数是什么样的吗?

标签: react-native realm


【解决方案1】:

渲染的 SectionHeader 显示整数是因为您没有以正确的格式构造数据源,请参阅此处的文档:link

你需要构造类似的东西:

const todoItemsData = {
  categoryOne: [itemOne, itemTwo],
  categoryTwo: [itemThree, itemFour]
}

但是现在你所拥有的只是一个对象数组[realmItemOne, realmItemTwo],如果你只是传入一个对象数组来构造cloneWithRowsAndSections将使用的数据源,category参数@987654328 @ 将成为整数索引符合here,Object.keys(arrayOfObjects) 将返回[0, 1, 2, ...]

所以你想映射你的todoItemsResults 并构建这样的东西

const itemData = {}
todoItemsResults.forEach((item) => {
  if(itemData[item.Category] {
    itemData[item.Category].push(item)
  } else
    itemData[item.Category] = [];
  }
});

const mapStateToProps = (state, props) => ({
  dataSource: todoItemDS.cloneWithRowsAndSections(itemData),
}

对于未显示任何数据问题的渲染行,我认为是由于同样的问题,您在 renderRow 中调用的 item 参数应该是您的其中一个 todoItem 对象的数据属性。您可以尝试在 {item} 中替换 {item.value} 以查看您的设置中实际包含的项目。我相信如果您可以构建正确的数据来提供您的dataSource,这将得到解决。


关于收听 Realm 更新的后续 cmets: 你可以这样做

class DummyPage extends Component {
  constructor(props) {
    super(props)
    this.realmUpdated = this.realmUpdated.bind(this);
    realm.objects('todoItem').addListener('change', this.realmUpdated);
  }

  componentWillUnmount() {
    realm.objects('todoItem').removeListener('change', this.realmUpdated);
  }

  realmUpdated() {
    this.forceUpdate();
  }

  render() {
    //build your data source in here and render the sectionList
  }

}

【讨论】:

  • 但在这种情况下,领域不会自动更新列表视图。有没有其他解决方案可以解决这个问题?
  • @FerasOdeh,你可以利用Realm的监听机制:realm.io/docs/javascript/latest/#notifications,强制更新你的页面组件。这将从您的领域中读取最新的最新值并重新渲染列表
  • 我添加了用于收听通知的代码。但是,它无法正常工作。你能帮忙吗?
  • @FerasOdeh 我觉得这值得提出另一个问题,这个问题最初只是为了弄清楚为什么 SectionList 没有呈现正确的行和标题部分数据。提出另一个问题将使其他人能够就 Realm 自动更新问题做出贡献。
  • @FerasOdeh 看到您更新的编辑,我认为这不起作用,因为领域更改将重新计算并返回新的 itemData 但它不会触发您页面的重新呈现。因此,如果您尝试按照我上面的 sn-p,删除您的 getTodoItems 中与列表器相关的代码并在渲染中调用 getTodoItems,并使用返回的数据重建 dataSource,并让 Realm 更新触发页面 forceUpdate,应该可以的。
猜你喜欢
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多