javascript - flatlist - React-Native Actualización de la vista de lista DataSource
listitem react native elements style (3)
En caso de que alguien se encuentre con este problema como yo, aquí está la solución completa.
Básicamente, parece que hay un error con el componente ListView y necesita reconstruir cada elemento que cambia en el origen de datos para que ListView lo vuelva a dibujar.
Aquí hay un ejemplo de trabajo: https://rnplay.org/apps/GWoFWg
Primero, cree la fuente de datos y una copia de la matriz y guárdelos en el estado. En mi caso, los foods
son la matriz.
constructor(props){
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
dataSource: ds.cloneWithRows(foods),
db: foods,
};
}
Cuando desee cambiar algo en la fuente de datos, haga una copia de la matriz que guardó en el estado, reconstruya el elemento con el cambio y luego guarde la nueva matriz con el cambio de nuevo al estado (tanto db como datasource).
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,
});
}
Tengo una aplicación de iOS que estoy haciendo con react-native. La clase Game contiene un componente ListView. Establecí el estado en el constructor e dataSource
un dataSource
. Tengo una matriz de datos codificados por ahora que this.state.ds
en una propiedad de estado diferente ( this.state.ds
). Luego en el componentDidMount
utilizo el método cloneWithRows
para clonar my this.state.ds
como mi dataSource para la vista. Eso es bastante estándar en lo que respecta a ListViews y funciona bien. Aquí está el código:
/**
* 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)}>
</ListView>
);
}
}
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
El problema que estoy teniendo viene en el método pressRow
. Cuando el usuario presiona la fila, me gustaría que la selección cambie y que muestre el cambio en el dispositivo. A través de algunas depuraciones, he notado que aunque estoy cambiando la propiedad Selection
del objeto en la matriz newDs
, la misma propiedad cambia en el objeto en this.state.ds
y de manera similar cambia el objeto en this.state.dataSource._dataBlob.s1
. Mediante una mayor depuración, he descubierto que, dado que esas otras matrices han cambiado, el objeto DataSource de ListView no reconoce el cambio porque cuando establezco el estado y se llama a rowHasChanged
, la matriz que this.state.dataSource._dataBlob.s1
coincide con la matriz this.state.dataSource._dataBlob.s1
y por lo tanto no se ve como un cambio y no se renueva.
¿Algunas ideas?
Prueba esto:
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)
})
}
Esto debería hacer una copia de la matriz, que luego se puede modificar independientemente de la matriz original en this.state.ds
.
reaccionar es lo suficientemente inteligente como para detectar cambios en dataSource y si la lista debe volver a procesarse. Si desea actualizar listView, cree nuevos objetos en lugar de actualizar las propiedades de los objetos existentes. El código se vería así:
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
});