Newby Coder header banner

Passing Data between screens in React Native

cl-react-native-screen-data-transfer

Alternatives of passing data between screens/pages in React Native

Following are some options of passing data between screens

Using props

 <SomeComponent style={{ color:'blue'}}, someProp={someData}></SomeComponent>
constructor(props) {
    super(props);
    aVar = this.props.someProp;
}

Using local storage

Local storage such as shared preferences or json storage can be used to store and retrieve data in multiple pages

Using local or remote database

Similar to local storage, databases can be used to imitate data communication between screens

Using callbacks

Callbacks which can be passed as prop to a component can be used to transfer data to and fro

Using navigator

Navigator object which is received by implementing react-navigation-stack and react-navigation modulesis accessible as prop to each screen provided in the declaration of the stack navigator

This navigator object allows to access its state, which contains the data passed from the page/screen that initiates the navigation


Example provided below implements navigator and callback for passing data between screens

Creating new React Native App

Check React Native Installation for installation related info

Use react-native init command to create a new React Native project (here named NcScreenDataTransfer)

react-native init NcScreenDataTransfer

This creates a directory named NcScreenDataTransfer and initializes it as a react native application directory

This can be skipped in case an existing react native project is being integrated into


Dependency

Since this example uses NavigationDrawer component, related packages have to be added

Go to project directory (here NcScreenDataTransfer)

cd NcScreenDataTransfer

Add react-navigation react-navigation-drawer && react-navigation-stack and associated dependencies to current project using yarn

yarn add react-navigation react-navigation-drawer react-navigation-stack \
react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens

or using npm

npm install react-navigation react-navigation-drawer react-navigation-stack \
react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens --save

iOS

After yarn add command, cd into ios folder inside project directory

cd ios

Use pod command to install any required CocoaPods dependencies:

pod install

App Code

Following is code ofr App.js and UserPage.js

App.js contains ListPage Component to display a list of users and allows to select a user whose data is passed to UserPage

Check inline comments

App.js
import React, { Component } from 'react';
import { StyleSheet, View, Button, TextInput, FlatList, Text, TouchableOpacity  } from 'react-native';

import { createAppContainer } from 'react-navigation';
import { createStackNavigator} from 'react-navigation-stack';

import UserPage from './UserPage';


//List page which displays a list of users
export default class ListPage extends Component {
  constructor(props) {
    super(props);
    // an array with data of users is declared as state
    this.state = {
      users: [
        {key: 'Devin'},
        {key: 'Dan'},
        {key: 'Dominic'},
        {key: 'Jackson'},
        {key: 'James'},
        {key: 'Joel'},
        {key: 'John', number:''},
        {key: 'Jillian', number: '373'},
        {key: 'Jimmy'},
        {key: 'Julie'},
      ]
    };
  }

  static navigationOptions = {
    title: 'UserList Page',
  };

  // receives updated value(number) for a key and updates users array
  editCallback(key, value) {
    var copy = [];
    for(var i=0; i<this.state.users.length; i++) {
      if(this.state.users[i].key == key) {
        copy.push({key: key, number: value});
      }
      else {
        copy.push(this.state.users[i]);
      }
    }
    this.setState({
      users: copy
    });
  };

  // navigate to Userpage while passing data of a user along-with
  // a callback function is also passed which receives updates done on Userpage
  navigateToPage(item) {
    const { navigate } = this.props.navigation;
    navigate('UserPage', {
      name: item.key,
      number: item.number ? item.number + '': '',
      // this has to be a lambda and cannot be replaced by 'this.editCallback' 
      // due to the use of 'this' keyword inside editCallback()
      editCallback: (key, value) => this.editCallback(key, value)
    })
  }

  // returns layout for each item of array
  renderItem(item) {
    var numberView = null;
    if(item.number && item.number.length > 0) {
      numberView = <Text style={styles.number}>{item.number}</Text>
    }
    return (
      // button to navigate to the page of an item (user)
      <TouchableOpacity style={styles.item} onPress={() => this.navigateToPage(item)}>
        <Text>{item.key}</Text>
        {numberView}
      </TouchableOpacity>
    );
  }

  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.users}
          renderItem={({item}) => this.renderItem(item) }
        />
      </View>
    );
  };
}

const App = createStackNavigator(
  //list of pages/screens which can be navigated to
  {
    ListPage: { screen: ListPage },
    UserPage: { screen: UserPage },
  },
  // initial page
  {
    initialRouteName: 'ListPage',
  }
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    padding: 16,
  },
  input: {
    width: 200,
    height: 44,
    padding: 10,
    marginBottom: 10,
    backgroundColor: '#DBDBD6',
  },
  item: {
    backgroundColor: 'lightblue',
    width: 200,
    padding: 10,
    margin: 2,
    flex: 1,
    flexDirection: 'row'
  },
  number: {
    position : 'absolute',
    right:20,
    alignSelf: 'center'
  }
});
export default createAppContainer(App);

UserPage component allows to update number for a user which is sent through the callback provided to it, to ListPage

UserPage.js
import React, { Component } from 'react';
import { StyleSheet, View, Text, TextInput } from 'react-native';


export default class UserPage extends Component {
  static navigationOptions = {
    title: 'User Page',
  };
  constructor(props) {
    super(props);
    // 'navigation' prop contains a 'state' with attribute 'params'
    // which holds the data passed to 'navigate()' function of previous screen
    this.state = {
      data: this.props.navigation.state.params
    };
  }

  render() {
    const { name, number, editCallback } = this.state.data;
    return (
      <View style={styles.container}>
        <Text> Page for </Text>
        <Text style={styles.TextStyle}>
          {name}
        </Text>
        // changes to TextInput invokes callback function to which the updated number is passed
        <TextInput
          value={number}
          onChangeText={(numberEdit) => {
            this.state.data.number = numberEdit;
            this.setState({});
            editCallback(name, numberEdit); }
          }
          placeholder={'Enter some number'}
          style={styles.input}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    margin: 50,
    alignItems: 'center',
    justifyContent: 'center',
  },
  TextStyle: {
    fontSize: 23,
    textAlign: 'center',
    color: '#f00',
  },
  input: {
    backgroundColor: '#cff'
  }
});

Run instructions

Running in Android

cd into project directory (here NcScreenDataTransfer)

cd NcScreenDataTransfer

Run metro server to serve js

react-native start

Go to project directory in another terminal tab

Enter following run command for Android:

react-native run-android
cl-react-native-screen-data-transfer

Running in ios

cd into project directory (here NcScreenDataTransfer)

cd NcScreenDataTransfer

Enter following command :

react-native run-ios

This might take some time


If the app shows error about metro server not configured (check Running an App in iOS), then run metro server in another tab:

react-native start

Reload the app

Re-run react-native run-ios command if reloading doesn't work

cm-react-native-screen-data-transfer-as1cm-react-native-screen-data-transfer-as2cm-react-native-screen-data-transfer-as3
cm-react-native-screen-data-transfer-as4cm-react-native-screen-data-transfer-as5