我知道之前已经提出此问题,请参阅here,here和here。
然而,没有一个答案/评论令人满意。它们要么告诉您克隆没有解决问题的数据,要么在ListView上设置一个唯一的键来解决问题,但会创建一个新的。
当您在ListView上设置唯一键并在删除后更新它时,整个视图会再次呈现并滚动到顶部。向下滚动列表以删除项目的用户希望列表保持其位置。
这是一个人为的例子,使用我所假设的克隆数据的正确方法:
var ListViewExample = React.createClass({
getInitialState() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => {
r1 !== r2
}});
var rows = ['row 1', 'row 2', 'row 3'];
return {
dataSource: ds.cloneWithRows(rows),
};
},
_deleteRow() {
var rows = ['row 1', 'row 3'];
this.setState({dataSource: this.state.dataSource.cloneWithRows(rows)})
},
renderRow(rowData, sectionID, rowID) {
return <TouchableOpacity onPress={this._deleteRow}
style={{height: 60, flex: 1, borderBottomWidth: 1}}>
<Text>{rowData}</Text>
</TouchableOpacity>
},
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
);
}
});
here你可以看到它的gif动作,其中错误的行被删除了。另一种方法是,设置ListView的key
道具会删除正确的行,但正如我所说的那样会导致列表滚动到顶部。
更新
我已经接受了Nader的回答,但这似乎不是正确的方法,因为它不会在dataSource上调用rowHasChanged
。它也不符合ListView文档。它确实解决了我的问题所以我将其标记为答案,但我觉得这是一个解决方法,而不是正确的解决方案
另一个更新
好的,这很尴尬,但我的rowHasChanged
函数缺少return
语句。我想我的咖啡中含有太多的ES6糖。
总而言之,如果你搞砸了rowHasChanged
功能,this._ds
会因某种原因而失效。如果你做的事情,从你开始的正确方法应该使用如下:
this.setState({
dataSource: this.state.dataSource.cloneWithRows(rows)
});
更新dataSource
时。
还要记住,您需要一个新的rows
数据库。使用cloneWithRows(rows.push(newRow)
等内容对其进行变更将无法正常工作,而cloneWithRows(rows.concat([newRow])
将会有效。
答案 0 :(得分:5)
我认为问题在于您是根据以前的ListView.DataSource实例设置数据源。我已经设置了我正在谈论的here的演示,并将下面的示例与另一种方法相结合。
尝试这样做:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
ListView
} = React;
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => { r1 !== r2 }});
var SampleApp = React.createClass({
getInitialState() {
var rows = ['row 1', 'row 2', 'row 3'];
return {
dataSource: ds.cloneWithRows(rows),
};
},
_deleteRow() {
var rows = ['row 1', 'row 3'];
this.setState({dataSource: ds.cloneWithRows(rows)})
},
renderRow(rowData, sectionID, rowID) {
return <TouchableOpacity onPress={this._deleteRow}
style={{height: 60, flex: 1, borderBottomWidth: 1}}>
<Text>{rowData}</Text>
</TouchableOpacity>
},
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
);
}
});
https://rnplay.org/apps/YGBcIA
您还可以在renderRow中使用rowID来标识要删除的项目,然后在删除功能中重置dataSource的状态。
查看我设置here的示例。此外,代码如下:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
ListView
} = React;
var rows = ['row 1', 'row 2', 'row 3'];
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => {
r1 !== r2
}});
var SampleApp = React.createClass({
getInitialState() {
return {
dataSource: ds.cloneWithRows([]),
rows: rows
};
},
componentDidMount() {
this.setState({
dataSource: ds.cloneWithRows( this.state.rows )
})
},
_deleteRow(rowID) {
this.state.rows.splice(rowID, 1)
this.setState({
dataSource: ds.cloneWithRows( this.state.rows ),
})
},
renderRow(rowData, sectionID, rowID) {
return <TouchableOpacity onPress={ () => this._deleteRow(rowID) }
style={{height: 60, flex: 1, borderBottomWidth: 1}}>
<Text>{rowData}</Text>
</TouchableOpacity>
},
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 28,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
fontSize: 19,
marginBottom: 5,
},
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);