J'écris une application en utilisant Expo (framework React Native). Chaque fois que l'état d'un composant est modifié avec la méthode setState (...), le composant doit effectuer un nouveau rendu pour afficher les dernières données d'état. Cela fonctionne avec les composants de base de React Native tels que View, Text, Button (j'ai essayé ces trois éléments), mais cela ne rend pas ici, où j'utilise le composant personnalisé TabView. Ceci est indiqué dans la documentation sur le composant:
"Toutes les scènes rendues avec SceneMap sont optimisées à l'aide de React.PureComponent et ne sont pas rendues à nouveau lorsque les accessoires ou les états des parents changent. Si vous avez besoin de plus de contrôle sur la mise à jour de vos scènes ( par exemple - déclencher un nouveau rendu même si navigationState n'a pas changé), utilisez directement renderScene au lieu d'utiliser SceneMap. "
Je ne comprends pas très bien comment gérer cela. Je voudrais que le composant soit à nouveau rendu chaque fois que l'état est modifié, dans ce cas, après avoir cliqué sur le bouton et appelé la fonction writeData ().
La documentation du composant TabView est ici: https://github.com/react-native-community/react-native-tab- voir .
import React from 'react'; import { TabView, SceneMap } from 'react-native-tab-view'; import { StyleSheet, Text, View, Dimensions, Button, ToastAndroid } from 'react-native'; export default class MojTabView extends React.Component { state = { index: 0, routes: [ { key: 'allEvents', title: 'Všetko' }, { key: 'sortedEvents', title: 'Podľa druhu' }, { key: 'myEvents', title: 'Moje akcie'} ], name: "Robert" }; MyEvents = () => ( <View style={[styles.scene, { backgroundColor: 'white' }]}> <Text>Some content</Text> <Button style={{ margin: 5 }} onPress={this.writeData} title="Write data" color="#841584" /> <Text>Name in state: {this.state.name}</Text> </View> ); SortedEvents = () => ( <Text>Some content</Text> ); AllEvents = () => ( <Text>Some other content</Text> ); writeData = () => { ToastAndroid.show("button click works!", ToastAndroid.LONG); this.setState({ name: "Richard"}); } render() { return ( <TabView navigationState={this.state} renderScene={SceneMap({ allEvents: this.AllEvents, myEvents: this.MyEvents, sortedEvents: this.SortedEvents })} onIndexChange={index => this.setState({ index })} initialLayout={{ width: Dimensions.get('window').width }} /> ); }
}
J'ai passé quelques heures à essayer d'y parvenir, sans solution. C'est ma première question StackOverflow, merci.
3 Réponses :
Les deux éléments d'état qui devraient déclencher le nouveau rendu de votre TabView
sont:
Ils l'ont fait à des fins d'optimisation des performances
si vous voulez forcer le rendu de votre TabView
si vous modifiez une autre valeur d'état qui n'a rien à voir avec ces valeurs ... alors selon la documentation ... vous avez besoin pour fournir votre propre implémentation pour renderScene
comme:
renderScene = ({route, jumpTo}) => { commutateur (route.key) { cas 'musique': revenir ; cas 'albums': revenir ; } };
dans ce cas:
Vous devez vous assurer que vos itinéraires individuels implémentent un shouldComponentUpdate pour améliorer les performances.
D'accord, j'ai trouvé une solution un peu différente pour ce problème, mais merci d'avoir expliqué un peu.
Oui, je l'écris :)
Que faire si je souhaite simplement restituer le contenu de dans le cadre de ma scène, mais pas nécessairement la vue à onglets dans ce cas.
D'accord, j'ai enfin pu trouver une bonne solution. Le but est de définir le contenu des onglets / routes individuels dans un fichier séparé comme un composant React Native typique avec son propre état, pas à l'intérieur de ce composant MyTabView, comme cela est fait même dans l'exemple de la documentation sur TabView. Ensuite, cela fonctionne comme il se doit.
Exemple simple: Voici le contenu de l'un des onglets:
import MyExampleTab from './MyExampleTab' ... export default class MyTabView extends React.Component { ... render() { return ( <TabView navigationState={this.state} renderScene={SceneMap({ ... someKey: MyExampleTab, ... })} onIndexChange={index => this.setState({ index })} initialLayout={{ width: Dimensions.get('window').width }} /> )
Voici comment je le référence dans le composant MyTabView:
import React from 'react'; import { Text, View, Button } from 'react-native'; export default class MyExampleTab extends React.Component { state = { property: "Default value", } writeData = () => { this.setState({ property: "Updated value" }) } render() { return ( <View> <Button style={{ margin: 5 }} onPress={this.writeData} title="Change the state and re-render!" color="#841584" /> <Text>Value of state property: {this.state.property}</Text> </View> ) } }
Je n'utilise donc pas
, comme je le ferais normalement en utilisant un composant personnalisé, mais je l'écris tel quel, MyExampleTab
. Ce qui est tout à fait logique. Et sur le bouton, cliquez sur les changements d'état et l'onglet ré-rend.
Comment puis-je passer des accessoires avec cette approche?
En vous basant sur ce que @druskacik a écrit ci-dessus, vous pouvez également transmettre un composant avec des accessoires
import MyExampleTab from './MyExampleTab' ... export default class MyTabView extends React.Component { ... render() { return ( <TabView navigationState={this.state} renderScene={SceneMap({ ... someKey:() => <MyExample foo={foodata} />, ... })} onIndexChange={index => this.setState({ index })} initialLayout={{ width: Dimensions.get('window').width }} /> )
Vous devez fournir votre propre implémentation pour
renderScene
si vous voulez forcer le nouveau rendu à chaque changement d'état ... car SceneMap qu'ils fournissent est unPureComponent
(ne se restitue pas lorsque les accessoires ou les états du parent changent)Avez-vous une idée / un indice sur la manière de réaliser cette propre implémentation?
consultez la réponse plz