web-dev-qa-db-fra.com

React Native Pass properties on navigator pop

J'utilise NavigatorIOS sur mon application native React. Je souhaite transmettre certaines propriétés lorsque je reviens à l'itinéraire précédent.

Un exemple de cas: je suis dans une page de formulaire. Après avoir soumis des données, je veux revenir à l'itinéraire précédent et faire quelque chose en fonction des données soumises

Comment dois-je faire ça?

21
Habibi

Pourriez-vous passer une fonction de rappel sur les accessoires du navigateur lorsque vous poussez la nouvelle route et appelez-la avec les données du formulaire avant de passer à la route précédente?

22
Tarrence

Exemple de code montrant comment utiliser un rappel avant pop. C'est spécifiquement pour Navigator et non NavigatorIOS mais un code similaire peut également être appliqué pour cela.

Vous avez Page1 et Page2. Vous passez de Page1 à Page2, puis revenez à Page1. Vous devez passer une fonction de rappel de Page2 qui déclenche du code dans Page1 et seulement après cela, vous reviendrez à Page1.

À la page 1 -

_goToPage2: function() {
  this.props.navigator.Push({
    component: Page2,
    sceneConfig: Navigator.SceneConfigs.FloatFromBottom,
    title: 'hey',
    callback: this.callbackFunction,
  })
},

callbackFunction: function(args) {
  //do something
  console.log(args)
},

À la page 2 -

_backToPage1: function() {
  this.props.route.callback(args);
  this.props.navigator.pop();
},

La fonction "callbackFunction" sera appelée avant "pop". Pour NavigatorIOS, vous devez faire le même rappel dans "passProps". Vous pouvez également transmettre des arguments à ce rappel. J'espère que ça aide.

23
mutp

Vous pouvez utiliser AsyncStorage, enregistrer une valeur sur le composant enfant, puis appeler navigator.pop ():

AsyncStorage.setItem('postsReload','true');
this.props.navigator.pop();

Dans le composant parent, vous pouvez le lire à partir d'AsyncStorage:

async componentWillReceiveProps(nextProps) {
    const reload =  await AsyncStorage.getItem('postsReload');
    if (reload && reload=='true')
    {
       AsyncStorage.setItem('postsReload','false');
       //do something
    }
  }
2
Vladislav

Pour NavigatorIOS, vous pouvez également utiliser replacePreviousAndPop ().

Code:

'use strict';

var React = require('react-native');
var {
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  AppRegistry,
  NavigatorIOS
} = React;

var MainApp = React.createClass({
  render: function() {
    return (
      <NavigatorIOS
          style={styles.mainContainer}
          initialRoute={{                   
            component: FirstScreen,
            title: 'First Screen',
            passProps: { text: ' ...' },
        }}
      />
    );
  },
});

var FirstScreen = React.createClass({
  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.helloText}>
              Hello {this.props.text}
        </Text>
        <TouchableOpacity 
            style={styles.changeButton} onPress={this.gotoSecondScreen}>
            <Text>Click to change</Text>
        </TouchableOpacity>      
      </View>
    );
  },
  gotoSecondScreen: function() {
        console.log("button pressed");
    this.props.navigator.Push({
        title: "Second Screen",
      component: SecondScreen
    });
    },
});

var SecondScreen = React.createClass({
  render: function() {    
    return (
      <View style={styles.container}>
        <Text style={styles.helloText}>
          Select a greeting
        </Text>
        <TouchableOpacity 
            style={styles.changeButton} onPress={() => this.sayHello("World!")}>
            <Text>...World!</Text>
        </TouchableOpacity>
        <TouchableOpacity 
            style={styles.changeButton} onPress={() => this.sayHello("my Friend!")}>
            <Text>...my Friend!</Text>
        </TouchableOpacity>   
      </View>
    );
  },
  sayHello: function(greeting) {
        console.log("world button pressed");
    this.props.navigator.replacePreviousAndPop({
        title: "First Screen",
      component: FirstScreen,
      passProps: {text: greeting}
    });
    }
});


var styles = StyleSheet.create({
  mainContainer: {
        flex: 1,
        backgroundColor: "#eee"
  },
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    marginTop: 50,    
  },
  helloText: {
    fontSize: 16,
  },
  changeButton: {
    padding: 5,
    borderWidth: 1,
    borderColor: "blue",
    borderRadius: 4,
    marginTop: 20
  }
});



AppRegistry.registerComponent("TestApp", () => MainApp);

Vous pouvez trouver l'exemple de travail ici: https://rnplay.org/apps/JPWaPQ

J'espère que ça aide!

1
andreaswienes

J'ai eu le même problème avec React Navigateur natif que j'ai réussi à résoudre en utilisant EventEmitters and Subscribables. Cet exemple ici était vraiment utile: https://colinramsay.co.uk/2015 /07/04/react-native-eventemitters.html

Tout ce que j'avais à faire était de mettre à jour ES6 et la dernière version de React Native.

Niveau supérieur de l'application:

import React, { Component } from 'react';
import {AppRegistry} from 'react-native';
import {MyNavigator} from './components/MyNavigator';
import EventEmitter from 'EventEmitter';
import Subscribable from 'Subscribable';

class MyApp extends Component {
    constructor(props) {
        super(props);
    }
    componentWillMount() {
        this.eventEmitter = new EventEmitter();
    }
  render() {
    return (<MyNavigator events={this.eventEmitter}/>);
  }
}

AppRegistry.registerComponent('MyApp', () => MyApp);

Dans la fonction _renderScene de votre navigateur, assurez-vous d'inclure l'accessoire "events":

_renderScene(route, navigator) {
    var Component = route.component;
    return (
        <Component {...route.props} navigator={navigator} route={route} events={this.props.events} />
    );
}

Et voici le code du composant FooScreen qui rend une vue de liste.

(Notez que react-mixin a été utilisé ici pour vous abonner à l'événement. Dans la plupart des cas, les mixins doivent être évités en faveur de composants d'ordre supérieur mais je n'ai pas pu trouver un moyen de contourner dans ce cas):

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  ListView,
  Text
} from 'react-native';
import {ListItemForFoo} from './ListItemForFoo';
import reactMixin from 'react-mixin'
import Subscribable from 'Subscribable';

export class FooScreen extends Component {
  constructor(props) {
    super(props);

    this._refreshData = this._refreshData.bind(this);
    this._renderRow = this._renderRow.bind(this);

    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

    this.state = {
      dataSource: ds.cloneWithRows([])
    }
  }

  componentDidMount(){
    //This is the code that listens for a "FooSaved" event.
    this.addListenerOn(this.props.events, 'FooSaved', this._refreshData);
    this._refreshData();
  }

  _refreshData(){
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(//YOUR DATASOURCE GOES HERE)
    })
  }
  _renderRow(rowData){
      return <ListItemForFoo 
          foo={rowData} 
          navigator={this.props.navigator} />;
  }
  render(){
    return(
      <ListView
      dataSource={this.state.dataSource}
      renderRow={this._renderRow}
      />
      )

  }
}
reactMixin(FooScreen.prototype, Subscribable.Mixin);

Finalement. Nous devons réellement émettre cet événement après avoir enregistré un Foo:

Dans votre composant NewFooForm.js, vous devriez avoir une méthode comme celle-ci:

  _onPressButton(){
    //Some code that saves your Foo

     this.props.events.emit('FooSaved'); //emit the event
     this.props.navigator.pop();  //Pop back to your ListView component
  }
1
Kenji Crosland