React Native Pass properties on navigator pop
Asked Answered
I

6

21

I'm using NavigatorIOS on my react native app. I want to pass some properties when navigating back to previous route.

An example case: I'm in a form page. After submitting data, I want to go back to the previous route and do something based on the submitted data

How should I do that ?

Interscholastic answered 5/4, 2015 at 23:53 Comment(1)
You've accepted an answer. Any chance you care to share an example of what you did to get around the problem?Robins
A
23

Could you pass a callback func on the navigator props when you push the new route and call that with the form data before you pop to the previous route?

Additament answered 6/4, 2015 at 0:14 Comment(2)
Is it possible to give us an code example how did you solved it? Thank you.Beethoven
sorry, this has been a while. I just put "passProps" object when pushing the navigator to the 2nd page. This object contains a function property. In the 2nd page, I can call that function with this.props.(function name)Interscholastic
E
23

Code sample showing how to use a callback before pop. This is specifically for Navigator and not NavigatorIOS but similar code can be applied for that as well.

You have Page1 and Page2. You are pushing from Page1 to Page2 and then popping back to Page1. You need to pass a callback function from Page2 which triggers some code in Page1 and only after that you will pop back to Page1.

In Page1 -

_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)
},

In Page2 -

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

The function "callbackFunction" will be called before "pop". For NavigatorIOS you should do the same callback in "passProps". You can also pass args to this callback. Hope it helps.

Ehr answered 8/9, 2015 at 6:17 Comment(3)
i got the error msg "Can not read property 'callback' of undefined".Abyssal
@Abyssal pass route to your component in renderScene. renderScene(router, navigator){ return <Test navigator={navigator} router={router} />}Rosendorosene
Perfect answer.Lelahleland
H
2

You can use AsyncStorage, save some value on child Component and then call navigator.pop():

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

In parent Component you can read it from AsyncStorage:

async componentWillReceiveProps(nextProps) {
    const reload =  await AsyncStorage.getItem('postsReload');
    if (reload && reload=='true')
    {
       AsyncStorage.setItem('postsReload','false');
       //do something
    }
  }
Howey answered 25/9, 2016 at 16:53 Comment(0)
S
1

For NavigatorIOS you can also use 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);

You can find the working example here: https://rnplay.org/apps/JPWaPQ

I hope that helps!

Suzannsuzanna answered 1/10, 2015 at 13:57 Comment(1)
Together with adding external links you should provide a description of that answer because external links are likely to change and your answer will not be useful aymore.Zwickau
E
1

I had the same issue with React Native's navigator which I managed to solve using EventEmitters and Subscribables. This example here was really helpful: https://colinramsay.co.uk/2015/07/04/react-native-eventemitters.html

All I needed to do was update for ES6 and the latest version of React Native.

Top level of the app:

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

In the _renderScene function of your navigator, make sure you include the "events" prop:

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

And here is the code for the FooScreen Component which renders a listview.

(Note that react-mixin was used here in order to subscribe to the event. In most cases mixins should be eschewed in favor of higher order components but I couldn't find a way around it in this case):

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

Finally. We need to actually emit that event after saving a Foo:

In your NewFooForm.js Component you should have a method like this:

  _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
  }
Escudo answered 14/8, 2016 at 20:52 Comment(0)
I
0

This is an old question, but currently React Navigation's documentation for Passing params to a previous screen suggests that we use navigation.navigate() and pass whatever parameters we want the previous screen to have.

Impressment answered 20/4, 2022 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.