J'ai un problème avec le nouveau composant FlatList. Plus précisément, il ne restitue pas ses lignes, même si les accessoires qui en dépendent dépendent des modifications.
La documentation FlatList dit que:
Ceci est un PureComponent ce qui signifie qu'il ne sera pas rendu à nouveau si les accessoires restent peu profonds - égaux. Assurez-vous que tout votre renderItem fonction dépend est passé comme un accessoire qui n'est pas === après les mises à jour, sinon, votre interface utilisateur ne peut pas mettre à jour les modifications. Cela inclut les données prop et état du composant parent.
LA QUESTION
Cependant, étant donné que je modifie l'ID de l'élément selectedCategory - l'accessoire devant indiquer si la ligne est "sélectionnée" ou non -, je pense que les accessoires doivent être rendus. Est-ce que je me trompe?
J'ai vérifié les méthodes 'composantWillReceiveProps' des composants list et row, et la liste reçoit parfaitement la mise à jour, mais la méthode de cycle de vie de la ligne n'est jamais appelée.
Si j'inclue une valeur d'état booléenne inutile et aléatoire dans le composant liste, et la bascule dans les deux sens lorsque les accessoires sont mis à jour, cela fonctionne - mais je ne sais pas pourquoi?
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}
/>
LE CODE
La structure de mon code est la suivante: j'ai un composant conteneur avec toute la logique et l'état, qui contient un composant FlatList (présentation, aucun état), qui contient à nouveau une ligne de présentation personnalisée.
Container
Custom list component that includes the FlatList component
(presentational, stateless) and the renderRow method
Custom row (presentational, stateless)
Le conteneur comprend ce composant:
<CustomList
items={this.props.viewer}
onCategoryChosen={this._onCategoryChosen}
selectedCategory={this.state.report.selectedCategory}
/>
Liste customisée:
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>
);
}
}
(les données proviennent du relais)
Enfin la rangée:
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 ligne n’est pas très intéressante, mais je l’ai incluse pour montrer qu’elle est entièrement apatride et dépendante des accessoires de ses parents.
L'état est mis à jour comme suit:
_onCategoryChosen = category => {
var oldReportCopy = this.state.report;
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
L'état ressemble à ceci:
state = {
...
report: defaultStateReport,
};
const defaultStateReport = {
selectedCategory: {
id: 'some-long-od',
name: '',
},
...
};
Le problème ici réside dans le fait que
_onCategoryChosen = category => {
var oldReportCopy = this.state.report; // This does not create a copy!
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
Cela devrait être
_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 });
};
Les accessoires de FlatList restent les mêmes, votre fonction _renderRow
peut s’appuyer sur le paramètre selectedCategory
qui change (si ce n’est pas la première erreur), mais le composant FlatList ne le sait pas. Pour résoudre ce problème, utilisez le extraData
prop.
<FlatList
data={this.props.items.categories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
extraData={this.props.selectedCategory}
/>
Vous pouvez simplement résoudre ce problème en passant props à extraData in liste plate composant comme celui-ci,
<FlatList
data={this.props.data}
extraData={this.props}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
Je suis d'accord avec Nimelrian. De plus, si votre état est un tableau, vous pouvez créer un objet tableau à partir de l'état en procédant comme suit:
var oldReportCopy = Object.assign([], this.state.report);
Ensuite, utilisez la méthode .Push () pour y ajouter votre nouvel objet comme ceci:
oldReportCopy.Push(selectedCategory);
vous pouvez ensuite remettre ce nouvel objet Array à l'état suivant:
this.setState({ report: oldReportCopy });