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:
/**
* 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.
Any ideas?
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
.