React-Native更新列表视图数据源
我有一个iOS应用程序,我正在与反原生。 Game类包含一个ListView组件。 我在构造函数中设置状态并包含一个dataSource
。 我现在有一个硬编码的数据数组,我存储在不同的状态属性( this.state.ds
)。 然后在componentDidMount
我使用cloneWithRows
方法将我的this.state.ds
克隆为视图的dataSource。 就ListViews而言,这是非常标准的,并且运行良好。 这里是代码:
/** * Sample React Native App * https://github.com/facebook/react-native */ 'use strict'; var React = require('react-native'); var { StyleSheet, Text, View, ListView, TouchableHighlight } = React; class Games extends React.Component{ constructor(props){ super(props); var ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 != r2 }); this.state = { ds:[{AwayTeam: "TeamA", HomeTeam: "TeamB", Selection: "AwayTeam"},{AwayTeam: "TeamC", HomeTeam: "TeamD", Selection: "HomeTeam"}], dataSource:ds, } } componentDidMount(){ this.setState({ dataSource:this.state.dataSource.cloneWithRows(this.state.ds), }) } pressRow(rowData){ var newDs = []; newDs = this.state.ds; newDs[0].Selection = newDs[0] == "AwayTeam" ? "HomeTeam" : "AwayTeam"; this.setState({ dataSource: this.state.dataSource.cloneWithRows(newDs) }) } renderRow(rowData){ return ( <TouchableHighlight onPress={()=> this.pressRow(rowData)} underlayColor = '#ddd'> <View style ={styles.row}> <Text style={{fontSize:18}}>{rowData.AwayTeam} @ {rowData.HomeTeam} </Text> <View style={{flex:1}}> <Text style={styles.selectionText}>{rowData[rowData.Selection]}</Text> </View> </View> </TouchableHighlight> ) } render(){ return ( <ListView dataSource = {this.state.dataSource} renderRow = {this.renderRow.bind(this)}> </ListView> ); } } var styles = StyleSheet.create({ row:{ flex:1, flexDirection:'row', padding:18, borderBottomWidth: 1, borderColor: '#d7d7d7', }, selectionText:{ fontSize:15, paddingTop:3, color:'#b5b5b5', textAlign:'right' }, }); module.exports = Games
我遇到的问题来自pressRow
方法。 当用户按下该行时,我希望select更改,并在设备上呈现更改。 通过一些debugging,我已经注意到,即使我正在改变newDs
数组中的对象的Selection
属性,相同的属性在this.state.ds
的对象改变,并类似地改变this.state.dataSource._dataBlob.s1
的对象this.state.dataSource._dataBlob.s1
。 通过进一步的debugging,我发现由于那些其他数组已经改变,ListView的DataSource对象不能识别这个改变,因为当我设置状态并rowHasChanged
,它所克隆的数组与数组this.state.dataSource._dataBlob.s1
匹配this.state.dataSource._dataBlob.s1
,所以它看起来不像一个变化,不会重新渲染。
有任何想法吗?
尝试这个:
pressRow(rowData){ var newDs = []; newDs = this.state.ds.slice(); newDs[0].Selection = newDs[0] == "AwayTeam" ? "HomeTeam" : "AwayTeam"; this.setState({ dataSource: this.state.dataSource.cloneWithRows(newDs) }) }
这应该创build一个数组的副本,然后可以在this.state.ds
独立于原始数组进行this.state.ds
。
如果有人像我一样遇到这个问题,这里是完整的解决scheme。
基本上,似乎有一个ListView组件的错误,你需要重buildListView的数据源中改变的每个项目来重绘它。
以下是一个工作示例: https : //rnplay.org/apps/GWoFWg
首先,创build数据源和数组的副本并将其保存为状态。 在我的情况下, foods
是arrays。
constructor(props){ super(props); var ds = new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2, }); this.state = { dataSource: ds.cloneWithRows(foods), db: foods, }; }
当你想改变数据源中的东西时,把你保存到状态的数组复制一份,用改变来重build项目,然后保存新的数组,使其回到状态(db和datasource)。
onCollapse(rowID: number) { console.log("rowID", rowID); var newArray = this.state.db.slice(); newArray[rowID] = { key: newArray[rowID].key, details: newArray[rowID].details, isCollapsed: newArray[rowID].isCollapsed == false ? true : false, }; this.setState({ dataSource: this.state.dataSource.cloneWithRows(newArray), db: newArray, }); }
反应是足够聪明的来检测dataSource的变化,如果列表应该重新呈现。 如果你想更新listView,创build新的对象,而不是更新现有对象的属性。 代码看起来像这样:
let newArray = this._rows.slice(); newArray[rowID] = { ...this._rows[rowID], Selection: !this._rows[rowID].Selection, }; this._rows = newArray; let newDataSource = this.ds.cloneWithRows(newArray); this.setState({ dataSource: newDataSource });
你可以在Github上阅读更多关于类似的问题