2016-05-26 10 views
3

Ich bin ziemlich neu zu reagieren Native und einige Probleme mit dem Verständnis des gesamten Ökosystems davon. Wie auch immer, ich habe eine ListView und der Benutzer kann zu einer anderen View navigieren, um ein neues Element hinzuzufügen, das der Liste hinzugefügt wird. Wenn ich zurücktrete (Pop), wird die Liste nicht aktualisiert, da die Datenquelle in getInitialState zugewiesen wurde.React Native: Update-Ansicht (ListView) auf Navigator Pop

Wie kann ich die Ansicht zwingen, die Liste zu aktualisieren, wenn ich pop? Ist dies getan, indem die Route in onDidFocus des Navigators behandelt wird oder gibt es etwas, das ich dem eigentlichen ListView hinzufügen kann?

Haben eine verkleinerte Version des Codes zur Verfügung gestellt und es ist die Budget-Komponente und ihre Liste, die aktualisiert werden muss, wenn ein Pop-Ereignis aus dem Navigator war.

Index-Datei

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-Komponente

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} 
     /> 
    ); 
    } 
}; 

Hoffe, das ist genug für Sie, das Problem zu verstehen, danke!

Edit: Versucht, eine Funktion zu erreichen, die einen neuen Zustand mit Daten für die Liste von onDidFocus setzen wird. Da aber der Aufruf dieser Funktion über route.component.prototype.updateData (Daten) ist, this.setState returns „Kann nicht lesen Eigenschaft‚enqueueSetState‘undefinierte“

+0

Änderungen widerzuspiegeln, sollten Sie Zustand Datasource durch Methode this.setState ändern. So rufen Sie bei jeder Änderung someMethod und in diesem someMethod this.setState ({dataSource: newDataSource}) auf. – NeoAsh

+0

Ja, ich dachte, es könnte so gelöst werden, aber wie kann ich die Änderungen abfangen und eine Methode in dieser Komponente aufrufen. Von onDidFocus in meiner Hauptklasse kann ich nur auf die Route zugreifen oder kann ich vom untergeordneten Element der Liste auf die Methode zugreifen? Das ist von der Ansicht, die ein neues listitem hinzufügt, kann ich someMethod in BudgetList-Komponente aufrufen, die den Zustand aktualisieren wird, bevor ich pop? @NeoAsh – willedanielsson

+0

Können Sie den vollständigen Code bereitstellen? (bei Github oder wo auch immer Sie sich wohl fühlen). – NeoAsh

Antwort

0

So fand ich heraus, dass es sich dabei vermutlich um einen Fehler Mit dem Rendern von ListView in React Native und durch Hinzufügen von etwas weniger schönem Code, habe ich es zum Laufen gebracht.

Ich habe eine Methode onDidFocus zu meiner Index-Datei hinzugefügt, die jedes Mal aufgerufen wird, wenn eine Komponente angezeigt wird (damit sie verwendet werden kann, wenn der Benutzer die vorherige Ansicht aufruft). Wenn die Route in onDidFocus Budget war, gebe ich die Komponente erneut zurück. Ich zog auch die Daten aus, die in der Listview meinem Index verwendet wird, so Listview die Daten als eine Eigenschaft bekommt und wieder machen, wenn sie sich geändert hat:

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)} 
       /> 
     }/> 
    ) 
    } 
}); 

Weiter In BudgetComponent.js habe ich nur die Daten von Requisiten als einen Zustand gesetzt und diese Statusdaten verwendet, um sie als Requisiten an meine BudgetList-Komponente zu senden (ich habe sie auch in eine Klasse und nicht in eine Komponente geändert, aber das ist nicht wichtig):

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> 
    ) 
    }); 

Nun sollte dies aber wegen des Fehlers die DataSource in einem Li funktionieren st funktioniert nicht korrekt, also kann ich mit der Methode componentWillUpdate (die immer aufgerufen wird, wenn die Liste angezeigt wird) die Aktualisierung der Daten erzwingen. Um jedoch in einer Endlos-Schleife nicht stecken zu bleiben, musste ich überprüfen, ob die Daten aktualisiert werden sollen oder sonst wäre es in der Aktualisierung der Daten stecken bleiben:

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

I gelöst Dieses Problem mit componentDidMount, die jedes Mal aufgerufen wird, wenn die Komponente angezeigt wird. Diese Lösung funktioniert derzeit für mich.

Zum Beispiel

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

nicht sicher, ob dies geändert wurde, nachdem Sie gebucht haben, aber 'componentDidMount' wird nur nach dem anfänglichen Rendern aufgerufen. –

+0

Wahr, aber wenn 'navigator.pop()' aufgerufen wird, wird die aktuelle Szene ummount, und die vorherige Szene wird eingehängt, was 'componentDidMount' und' render' aufruft. Zumindest funktioniert das mit diesen Prämissen für mich. –

+0

hmm, ich könnte dann etwas falsch machen, denn das funktioniert nicht für mich. Ich habe am Ende ein Ereignis an die zugrunde liegende Szene gesendet, so dass es aktualisiert werden kann, bevor der aktuelle gepoppt wird. –