Javascript React-Native 更新列表视图数据源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31738671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React-Native Updating List View DataSource
提问by Brandon M
I have an iOS app I am making with react-native. The Game class contains a ListView component. I set the state in the constructor and include a dataSource
. I have a hardcoded array of data for right now that I store in a different state property (this.state.ds
). Then in the componentDidMount
I use the cloneWithRows
method to clone my this.state.ds
as my dataSource for the view. That is pretty standard as far as ListViews go and is working well. Here is the code:
我有一个用 react-native 制作的 iOS 应用。Game 类包含一个 ListView 组件。我在构造函数中设置状态并包含一个dataSource
. 我现在有一个硬编码的数据数组,我将其存储在不同的状态属性 ( this.state.ds
) 中。然后在componentDidMount
我使用该cloneWithRows
方法将 my 克隆this.state.ds
为视图的数据源。就 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)}
/>
);
}
}
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
The issue I am having comes in the pressRow
method. When the user presses the row, I would like the selection to change and for it to render the change on the device. Through some debugging, I have noticed that even though I am changing the Selection
property of the object in the newDs
array, the same property changes on the object in this.state.ds
and similarly changes the object in this.state.dataSource._dataBlob.s1
. Through further debugging, I have found that since those other arrays have changed, the ListView's DataSource object doesn't recognize the change because when I set the state and rowHasChanged
is called, the array it is cloning matches the array this.state.dataSource._dataBlob.s1
and so it doesn't look like a change and doesn't rerender.
我遇到的问题来自pressRow
方法。当用户按下该行时,我希望选择更改并使其在设备上呈现更改。通过一些调试,我注意到即使我改变了数组中Selection
对象的属性newDs
,同样的属性this.state.ds
在this.state.dataSource._dataBlob.s1
. 通过进一步调试,我发现由于其他数组发生了更改,ListView 的 DataSource 对象无法识别更改,因为当我设置状态并被rowHasChanged
调用时,它克隆的数组与该数组匹配this.state.dataSource._dataBlob.s1
,因此它看起来不像就像改变一样,不会重新渲染。
Any ideas?
有任何想法吗?
采纳答案by eddyjs
Try this:
尝试这个:
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 should make a copy of the array, which can then be modified independently of the original array in this.state.ds
.
这应该制作数组的副本,然后可以独立于this.state.ds
.
回答by Dev01
In case anyone comes across this issue like I did, here's the complete solution.
如果有人像我一样遇到这个问题,这里是完整的解决方案。
Basically, there seems to be a bug with the ListView component and you need to rebuild each item that changes in the datasource for the ListView to redraw it.
基本上,ListView 组件似乎存在一个错误,您需要重建数据源中更改的每个项目,以便 ListView 重新绘制它。
First, create the datasource and a copy of the array and save them to state. In my case, foods
is the array.
首先,创建数据源和数组的副本并将它们保存到状态。在我的情况下,foods
是数组。
constructor(props){
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
dataSource: ds.cloneWithRows(foods),
db: foods,
};
}
When you want to change something in the datasource, make a copy of the array you saved to the state, rebuild the item with the change and then save the new array with the change back to the state (both db and datasource).
当您想更改数据源中的某些内容时,请复制您保存到状态的数组,使用更改重建项目,然后将更改后的新数组保存回状态(db 和数据源)。
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,
});
}
回答by Dariy Dzyndra
react is smart enough to detect changes in dataSource and if the list should be re-rendered. If you want to update listView, create new objects instead of updating the properties of existing objects. The code would look something like this:
react 足够智能,可以检测 dataSource 中的更改以及是否应重新呈现列表。如果要更新 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
});
You can read more about similar issue on Github
您可以在 Github 上阅读有关类似问题的更多信息