react-native - source - react native flatlist update
Reactivo-nativo FlatList no volver a presentar fila cuando cambian props (3)
El problema aquí radica en el hecho de que
- Está mutando un segmento de estado existente en lugar de crear una copia mutada
_onCategoryChosen = category => {
var oldReportCopy = this.state.report; // This does not create a copy!
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
Esto debería ser
_onCategoryChosen = category => {
var oldReportCopy = Object.assign({}, this.state.report);
oldReportCopy.selectedCategory = category;
// setState handles partial updates just fine, no need to create a copy
this.setState({ report: oldReportCopy });
};
Las propiedades de FlatList siguen siendo las mismas, su función
_renderRow
puede basarse en la propiedad de categoríaselectedCategory
que cambia (si no es por el primer error), pero el componente FlatList no lo sabe. Para resolver esto, use el propextraData
.<FlatList data={this.props.items.categories.edges} renderItem={this._renderRow} horizontal={true} keyExtractor={(item, index) => item.node.id} extraData={this.props.selectedCategory} />
Tengo un problema con el nuevo componente FlatList. Específicamente, no redirige sus filas, aunque afirma que la fila depende de los cambios.
Los documentos de FlatList dicen que:
Este es un PureComponent, lo que significa que no se volverá a generar si los objetos permanecen igual de simples. Asegúrese de que todo de lo que depende su función renderItem se pasa como un elemento que no es === después de las actualizaciones, de lo contrario, es posible que su UI no se actualice en los cambios. Esto incluye la proposición de datos y el estado del componente principal.
LA PREGUNTA
Sin embargo, viendo que cambio un ID del elemento de categoría seleccionada - el elemento que debe indicar si la fila está ''seleccionada'' o no - creo que los elementos deben volver a enviarse. ¿Estoy equivocado?
Revisé los métodos ''componentWillReceiveProps'' tanto de la lista como de los componentes de la fila, y la lista recibe la actualización muy bien, pero el método del ciclo de vida de la fila nunca se llama.
Si incluyo un valor de estado booleano aleatorio e inútil en el componente de lista, y lo cambio de un lado a otro cuando se actualicen los accesorios, funciona, pero no sé por qué.
state = { updated: false };
componentWillReceiveProps(nextProps) {
this.setState(oldstate => ({
updated: !oldstate.updated,
}));
}
<FlatList
data={this.props.items.allAnimalCategories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
randomUpdateProp={this.state.updated}
/>
EL CÓDIGO
La estructura de mi código es la siguiente: tengo un componente contenedor con toda la lógica y el estado, que contiene un componente FlatList (presentación, sin estado), que a su vez contiene una fila de presentación personalizada.
Container
Custom list component that includes the FlatList component
(presentational, stateless) and the renderRow method
Custom row (presentational, stateless)
El contenedor incluye este componente:
<CustomList
items={this.props.viewer}
onCategoryChosen={this._onCategoryChosen}
selectedCategory={this.state.report.selectedCategory}
/>
Lista personalizada:
class CustomList extends Component {
_renderRow = ({ item }) => {
return (
<CustomListRow
item={item.node}
selectedCategory={this.props.selectedCategory}
onPressItem={this.props.onCategoryChosen}
/>
);
};
render() {
return (
<View style={_styles.container}>
<FlatList
data={this.props.items.categories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
randomUpdateProp={this.state.updated}
/>
</View>
);
}
}
(Los datos provienen de Relay)
Finalmente la fila:
render() {
const idsMatch = this.props.selectedCategory.id == this.props.item.id;
return (
<TouchableHighlight onPress={this._onItemPressed}>
<View style={_styles.root}>
<View style={[
_styles.container,
{ backgroundColor: this._getBackgroundColor() },
]}>
{idsMatch &&
<Image
style={_styles.icon}
source={require(''./../../res/img/asd.png'')}
/>}
{!idsMatch &&
<Image
style={_styles.icon}
source={require(''./../../res/img/dsa.png'')}
/>}
<Text style={_styles.text}>
{capitalizeFirstLetter(this.props.item.name)}
</Text>
</View>
<View style={_styles.bottomView}>
<View style={_styles.greyLine} />
</View>
</View>
</TouchableHighlight>
);
}
La fila no es tan interesante, pero la incluí para mostrar que es completamente apátrida y depende de los apoyos de sus padres.
El estado se actualiza así:
_onCategoryChosen = category => {
var oldReportCopy = this.state.report;
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
Estado se ve así:
state = {
...
report: defaultStateReport,
};
const defaultStateReport = {
selectedCategory: {
id: ''some-long-od'',
name: '''',
},
...
};
Estoy de acuerdo con Nimelrian. Además, si su estado es una matriz, puede crear un objeto de matriz a partir del estado haciendo lo siguiente:
var oldReportCopy = Object.assign([], this.state.report);
Luego use el método .push () para agregarle su nuevo objeto de esta manera:
oldReportCopy.push(selectedCategory);
A continuación, puede volver a establecer este nuevo objeto de matriz en el estado:
this.setState({ report: oldReportCopy });
Simplemente puede resolver este problema pasando los accesorios a extraData en un componente de lista plana como este,
<FlatList
data={this.props.data}
extraData={this.props}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>