React Native ListView:删除时删除了错误的行

React Native ListView:删除时删除了错误的行,listview,react-native,Listview,React Native,我知道以前有人问过这个问题,例如,见和 然而,没有一个答案/意见令人满意。它们要么告诉您克隆无法解决问题的数据,要么在ListView上设置一个唯一的键以解决问题,但创建一个新的键 在ListView上设置唯一键并在删除后更新时,整个视图将再次呈现并滚动到顶部。向下滚动列表以删除项目的用户希望列表保持其位置 下面是一个人为的例子,我认为这是克隆数据的正确方法: var ListViewExample=React.createClass({ getInitialState(){ var ds=新的

我知道以前有人问过这个问题,例如,见和

然而,没有一个答案/意见令人满意。它们要么告诉您克隆无法解决问题的数据,要么在ListView上设置一个唯一的键以解决问题,但创建一个新的键

在ListView上设置唯一键并在删除后更新时,整个视图将再次呈现并滚动到顶部。向下滚动列表以删除项目的用户希望列表保持其位置

下面是一个人为的例子,我认为这是克隆数据的正确方法:

var ListViewExample=React.createClass({
getInitialState(){
var ds=新的ListView.DataSource({rowHasChanged:(r1,r2)=>{
r1!==r2
}});
变量行=['第1行','第2行','第3行'];
返回{
数据源:ds.cloneWithRows(rows),
};
},
_deleteRow(){
变量行=['行1','行3'];
this.setState({dataSource:this.state.dataSource.cloneWithRows(rows)})
},
renderRow(行数据、节ID、行ID){
返回
{rowData}
},
render(){
返回(
);
}
});
您可以看到它的gif,其中错误的行被删除。另一种选择是,设置ListView的
道具确实会删除正确的行,但正如我所说的,会导致列表滚动到顶部

更新

我已经接受了纳德下面的回答,但这似乎不是正确的方法,因为它不调用数据源上的
rowHasChanged
。它也不符合ListView文档。它确实解决了我的问题,所以我将把它标记为答案,但我觉得这是一个解决方法,而不是正确的解决方案

另一次更新

好的,这很尴尬,但是我的
rowHasChanged
函数缺少
return
语句。我想我的咖啡里的ES6糖太多了

总之,如果你搞砸了你的
行hasChanged
函数,
这个.\u ds
会因为某种原因起作用。如果你一开始就用正确的方式做事,你可能应该使用以下方法:

this.setState({
  dataSource: this.state.dataSource.cloneWithRows(rows)
});
更新
数据源时


还要记住,您需要一个新的
datablob。使用类似于
cloneWithRows(rows.push(newRow)
的东西对其进行适当的变异将不起作用,而
cloneWithRows(rows.concat([newRow])
will.

我认为问题在于您正在基于前面的ListView.datasource实例设置数据源。我已经设置了一个演示,演示了我所说的内容,并将下面的示例与另一种方法放在一起

尝试这样做:

'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}
      />
    );
  }

});
“严格使用”;
var React=require('React-native');
变量{
评估学,
样式表,
文本,
看法
可触摸不透明度,
列表视图
}=反应;
var ds=新的ListView.DataSource({rowHasChanged:(r1,r2)=>{r1!==r2});
var SampleApp=React.createClass({
getInitialState(){
变量行=['第1行','第2行','第3行'];
返回{
数据源:ds.cloneWithRows(rows),
};
},
_deleteRow(){
变量行=['行1','行3'];
this.setState({dataSource:ds.cloneWithRows(rows)})
},
renderRow(行数据、节ID、行ID){
返回
{rowData}
},
render(){
返回(
);
}
});

您还可以在renderRow中使用rowID标识要删除的项,然后在delete函数中重置数据源的状态

请查看我设置的示例。此外,代码如下:

'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);
“严格使用”;
var React=require('React-native');
变量{
评估学,
样式表,
文本,
看法
可触摸不透明度,
列表视图
}=反应;
变量行=['第1行','第2行','第3行'];
var ds=新的ListView.DataSource({rowHasChanged:(r1,r2)=>{
r1!==r2
}});
var SampleApp=React.createClass({
getInitialState(){
返回{
数据源:ds.cloneWithRows([]),
行:行
};
},
componentDidMount(){
这是我的国家({
数据源:ds.cloneWithRows(this.state.rows)
})
},
_删除行(rowID){
this.state.rows.splice(rowID,1)
这是我的国家({
数据源:ds.cloneWithRows(this.state.rows),
})
},
renderRow(行数据、节ID、行ID){
返回此。\u deleteRow(rowID)}
样式={{高度:60,弹性:1,边界底部宽度:1}>
{rowData}
},
render(){
返回(
);
}
});
var styles=StyleSheet.create({
容器:{
弹性:1,
为内容辩护:“中心”,
对齐项目:“居中”,
背景颜色:“#F5FCFF”,
},
欢迎:{
尺寸:28,
textAlign:'中心',
差额:10,
},
说明:{
textAlign:'中心',
颜色:'#333333',
尺码:19,
marginBottom:5,
},
});
AppRegistry.registerComponent('SampleApp',()=>SampleApp);

你说得很对。谢谢!React Native网站上的电影教程以及ListView的文档用
dataSource:this.state.dataSource.cloneWithRows设置了新的状态,我想我以前没有想过用你的方式。再次感谢!太棒了,是的,ListView上的文档很好t他们不是最好的。我正在处理一个pull请求,希望他们会认为这是有意义的!我刚刚注意到,使用您上面描述的方法,
rowHasChanged
不会被调用。您可以通过将控制台日志放在那里来验证它。这不是预期的行为,不是吗?正如我所说的,React本机文档使用
this.state.dataSource.cloneWithRows
更新状态,而不是在一些全局
ds
对象上使用
ds.cloneWithRows
更新状态。哎呀,原来我的原始代码示例中有一个bug。请参阅上面的更新。如果它对其他人有帮助的话……对我来说,关键是在克隆之前对我的列表进行深度复制……所以在克隆之前埃维投掷