Javascript 反应本机更新列表视图数据源

Javascript 反应本机更新列表视图数据源,javascript,ios,arrays,datasource,react-native,Javascript,Ios,Arrays,Datasource,React Native,我用react native制作了一个iOS应用程序。游戏类包含一个ListView组件。我在构造函数中设置状态,并包含一个数据源。我现在有一个硬编码的数据数组,存储在不同的state属性中(this.state.ds)。然后在componentDidMount中,我使用cloneWithRows方法克隆我的this.state.ds作为视图的数据源。就ListView而言,这是相当标准的,并且工作得很好。代码如下: /** * Sample React Native App * https

我用react native制作了一个iOS应用程序。游戏类包含一个ListView组件。我在构造函数中设置状态,并包含一个
数据源
。我现在有一个硬编码的数据数组,存储在不同的state属性中(
this.state.ds
)。然后在
componentDidMount
中,我使用
cloneWithRows
方法克隆我的
this.state.ds
作为视图的数据源。就ListView而言,这是相当标准的,并且工作得很好。代码如下:

/**
 * 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)}
        />
    );
}
}
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
/**
*示例React本机应用程序
* https://github.com/facebook/react-native
*/
"严格使用",;
var React=要求(“React native”);
var{StyleSheet,Text,View,ListView,TouchableHighlight}=React;
类游戏扩展了React.Component{
建造师(道具){
超级(道具);
var ds=new ListView.DataSource({
行已更改:(r1,r2)=>r1!=r2
});
此.state={
ds:[
{AwayTeam:“TeamA”,HomeTeam:“TeamB”,选择:“AwayTeam”},
{AwayTeam:“TeamC”,HomeTeam:“TeamD”,选择:“HomeTeam”}
],
数据源:ds
};
}
componentDidMount(){
这是我的国家({
dataSource:this.state.dataSource.cloneWithRows(this.state.ds)
});
}
按ROW(行数据){
var newDs=[];
newDs=this.state.ds;
newDs[0]。Selection=newDs[0]=“AwayTeam”?“HomeTeam”:“AwayTeam”;
这是我的国家({
dataSource:this.state.dataSource.cloneWithRows(newDs)
});
}
renderRow(行数据){
返回(
this.pressRow(rowData)}
underlayColor=“#ddd”
>
{rowData.AwayTeam}@{rowData.HomeTeam}{''}
{rowData[rowData.Selection]}
);
}
render(){
返回(
);
}
}
var styles=StyleSheet.create({
行:{
弹性:1,
flexDirection:“行”,
填充:18,
边界宽度:1,
边框颜色:“d7d7d7”
},
选择文本:{
尺寸:15,
paddingTop:3,
颜色:“B5”,
text对齐:“右”
}
});
module.exports=游戏
我遇到的问题来自
pressRow
方法。当用户按下该行时,我希望选择更改,并使其在设备上呈现更改。通过一些调试,我注意到,即使我正在更改
newDs
数组中对象的
Selection
属性,在
this.state.ds
中对象的相同属性也会更改,并且类似地更改
this.state.dataSource.\u dataBlob.s1
中的对象。通过进一步调试,我发现由于其他数组已经更改,ListView的DataSource对象无法识别更改,因为当我设置状态并调用
rowHasChanged
时,它正在克隆的数组与数组
this.state.dataSource.\u 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)
    })

}

这应该是数组的一个副本,然后可以在
This.state.ds
中独立于原始数组进行修改。如果有人像我一样遇到这个问题,下面是完整的解决方案

基本上,ListView组件似乎有一个bug,您需要为ListView重新绘制数据源中更改的每个项

首先,创建数据源和数组的副本,并将它们保存到state。在我的例子中,
foods
是数组

constructor(props){
    super(props);
    var ds = new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
        dataSource: ds.cloneWithRows(foods),
        db: foods,
    };
}
如果要更改数据源中的某些内容,请将保存到状态的数组复制一份,使用更改重新生成该项,然后使用更改将新数组保存回状态(db和数据源)


react足够智能,可以检测数据源中的更改以及是否应该重新呈现列表。如果要更新listView,请创建新对象,而不是更新现有对象的属性。 代码如下所示:

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

您可以阅读更多关于类似的内容

非常感谢!我还必须采取另一个步骤才能使它起作用。出于某种原因,我不得不“清除”我试图改变的对象。因此,我只是将
newDs[0]
设置为一个新对象,并将我试图更改的对象的属性赋予它。当然,我更改了
选择
属性。将
this.state.ds.slice()
更改为
this.state.ds.slice(0)
以获得更好的性能。@TheNickyYo-为什么?文档中所说的未定义被视为0?
this.state.ds.slice()
不是一个函数,您应该能够手动重建整个对象:
var copy=object.assign({},obj)根据MDN文档:或者如果您更喜欢ES6语法:
newRows[rowId]={…this.\u sampleData[rowId],favorited:rowData.favorited?false:true}
this.db而不是this.state.db是否更好?
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
});