2016-05-26 4 views
3

Je suis assez nouveau pour Réagir Native et avoir un problème avec la compréhension de tout l'écosystème de celui-ci. Quoi qu'il en soit, j'ai un ListView et l'utilisateur peut naviguer vers une autre vue afin d'ajouter un nouvel élément qui sera ajouté à la liste. Quand je recule (pop) la liste n'est pas mise à jour car la source de données est assignée dans getInitialState.Réagir Natif: Mettre à jour l'affichage (ListView) sur le navigateur pop

Comment puis-je forcer la vue à mettre à jour la liste quand je saute? Est-ce fait en manipulant la route dans onDidFocus du navigateur ou est-ce que je peux ajouter quelque chose à la ListView actuelle?

Avoir fourni une version réduite du code et c'est le composant Budget et sa liste qui doit être mis à jour lorsqu'il y a eu un événement pop du navigateur.

Index fichier

var BudgetWatch_ReactNative = React.createClass({ 

    renderScene(route, navigator){ 
     if(route.name == 'Main'){ 
     return React.createElement(route.component, {navigator}); 
     } 
     if(route.name == 'Budgets'){ 
     return React.createElement(route.component, {navigator, realm}); 
     } 
    }, 

    onDidFocus(route){ 
     // Insert React Native magic? 
    }, 
    render() { 
     return (
     <Navigator 
      ref={(nav) => { navigator = nav; }} 
      style={{flex:1}} 
      initialRoute={{ name: 'Main', component: Main}} 
      renderScene={this.renderScene} 
      onDidFocus={this.onDidFocus} 
      navigationBar={ 
       <Navigator.NavigationBar 
       routeMapper={NavigationBarRouteMapper(realm)} 
       /> 
     }/> 
    ) 
    } 
}); 

Budget composants

class Budgets extends React.Component{ 
    render(){ 
     return (
     <View> 
      <BudgetList navigator = {this.props.navigator}/> 
     </View> 
    ) 
    } 
} 

var BudgetList = React.createClass({ 
    getInitialState: function() { 
     var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 
     return { 
     dataSource: ds.cloneWithRows(this.props.realm.objects('Budget')), 
     }; 
    }, 

    render: function() { 
     return (
     <ListView 
      dataSource={this.state.dataSource} 
      renderRow={this._renderRow} 
     /> 
    ); 
    } 
}; 

Espérons que cela suffit pour vous de comprendre le problème, merci!

Édition: Essayé pour atteindre une fonction qui définira un nouvel état avec des données pour la liste de onDidFocus. Mais depuis l'appel à cette fonction se fait par route.component.prototype.updateData (données), this.setState renvoie « Impossible de lire la propriété « enqueueSetState » undefined »

+0

pour refléter les changements, vous devez changer d'état de dataSource en utilisant la méthode this.setState. Donc, sur chaque someMethod d'appel de changement et dans cet appel someMethod this.setState ({dataSource: newDataSource}). – NeoAsh

+0

Ouais, je pensais que ce pourrait être résolu comme ça, mais comment puis-je attraper les changements et appeler une méthode dans ce composant. De onDidFocus dans ma classe principale je ne peux accéder à la route ou puis-je accéder à la méthode de l'enfant de la liste? C'est à partir de la vue qui ajoute un nouveau listitem, puis-je appeler someMethod dans BudgetList-component qui mettra à jour l'état avant que je pop? @NeoAsh – willedanielsson

+0

Pouvez-vous fournir le code complet? (chez github ou ailleurs où vous vous sentez à l'aise). – NeoAsh

Répondre

0

Je trouve que cela est censé être un bug avec le rendu de ListView dans React Native et en ajoutant du code moins beau, je l'ai fait fonctionner.

J'ai ajouté une méthode onDidFocus à mon fichier-index qui est appelée chaque fois qu'un composant est affiché (ceci peut être utilisé lorsque l'utilisateur passe à la vue précédente). Lorsque l'itinéraire dans onDidFocus était Budget, je renvoie le composant à nouveau. J'ai également déplacé les données qui est utilisée dans le ListView à mon index afin ListView obtient les données comme une propriété et sera réengendrer quand il a changé:

index.android.js

var BudgetWatch_ReactNative = React.createClass({ 

    renderScene(route, navigator){ 
     if(route.name == 'Main'){ 
     return React.createElement(route.component, {navigator}); 
     } 
     if(route.name == 'Budgets'){ 
      var data = realm.objects('Budget').sorted('name'); 
      return <Budgets navigator={navigator} realm={realm} data={data} /> 
     } 
    }, 

    onDidFocus(route){ 
     if(route.name==='Budgets'){ 
      var data = realm.objects('Budget').sorted('name'); 
      return <Budgets navigator={navigator} realm={realm} data={data} /> 
     } 
    }, 
    render() { 
     return (
     <Navigator 
      ref={(nav) => { navigator = nav; }} 
      style={{flex:1}} 
      initialRoute={{ name: 'Main', component: Main}} 
      renderScene={this.renderScene} 
      onDidFocus={this.onDidFocus} 
      navigationBar={ 
       <Navigator.NavigationBar 
       routeMapper={NavigationBarRouteMapper(realm)} 
       /> 
     }/> 
    ) 
    } 
}); 

Suivant dans BudgetComponent.js Je viens de définir les données des accessoires en tant qu'état et utilisé ces données d'état pour les envoyer comme accessoires à mon composant BudgetList (je l'ai également changé en classe et non en composant mais pas important):

var Budgets = React.createClass({ 
    getInitialState: function() { 
     var propsdata = this.props.data; 
     return { 
      data: propsdata, 
     }; 
    }, 

    render(){ 
     return (
     <View style={styles.container}> 
      <BudgetList data={this.props.data} realm={this.props.realm} navigator = {this.props.navigator} /> 
     </View> 
    ) 
    }); 

Maintenant, cela devrait fonctionner, mais en raison du bug, le DataSource dans un Li st ne fonctionne pas correctement donc en utilisant une méthode componentWillUpdate (qui est appelée tout le temps que la liste est affichée) je pourrais forcer la mise à jour des données. Toutefois, afin de ne pas se coincer dans une boucle sans fin, je devais vérifier si les données doivent être mises à jour ou bien il serait coincé dans la mise à jour des données:

BudgetList.js

var BudgetList = React.createClass({ 
    getInitialState: function() { 
     var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); 
     var data = this.props.data; 
     return { 
     data: this.props.data, 
     dataSource: ds.cloneWithRows(this.props.data), 
     }; 
    }, 

    componentWillUpdate (nextProps) { 
     if (this.state.dataSource._cachedRowCount !== this.props.data.length) { 
      this.setState({ 
      data: this.props.data, 
      dataSource: this.state.dataSource.cloneWithRows(this.props.data) 
      }) 
     } 
    }, 

    _renderRow: function(rowData: string, sectionID: number, rowID: number) { 
     return(
      <View> 
      <Text>{rowData.name}</Text> 
      </View> 
     ) 
    } 
}); 
-1

Je résolu ce problème en utilisant componentDidMount, qui est appelé chaque fois que le composant apparaît. Cette solution fonctionne actuellement pour moi.

Par exemple,

var ListPage = React.createClass({ 
    getInitialState() { 
    return { 
     dataSource: ds.cloneWithRows(this._generateRows(this.props.list)), 
     currentPosition: 'unknown' 
    } 
    }, 

    componentDidMount() { 
    this._reloadListView(); 
    }, 

    _reloadListView() { 
    this.setState({ 
     dataSource: ds.cloneWithRows(this.props.list), 
    }); 
    }, 

    _generateRows(list) { 
    rows = []; 
    list.forEach(function(item, index) { 
     rows.push(item); 
    }); 
    return rows 
    }, 

    _renderRow(rowData) { 
    return (
     <Text>{ 'id: ' + rowData[ 'id' ] + ' ' + rowData[ 'info' ][ 'value' ][ 'name' ]}</Text> 
    ); 
    }, 

    render() { 
    return (
     <ListView 
     dataSource = { this.state.dataSource } 
     renderRow = { this._renderRow } 
     /> 
    ) 
    }, 
}); 

module.exports = ListPage; 
+0

ne sais pas si cela a été changé après que vous avez publié, mais 'componentDidMount' est seulement appelé après le rendu initial. –

+0

vrai, mais quand le 'navigator.pop()' est appelée, la scène actuelle est umounted, et celui monté précédent, qui appelle '' componentDidMount' et render'. Au moins, avec ces locaux travaille pour moi. –

+0

hmm, je pourrais faire quelque chose de mal alors, parce que cela ne fonctionne pas pour moi. J'ai fini par envoyer un événement à la scène sous-jacente afin qu'il puisse être mis à jour avant que le courant ne se produise. –