Search code examples
reactjsreact-nativereact-native-router-flux

Passing props in react-native-flux-router


So I'm still a bit new to React Native, but I've got an app working nearly how I want it to. I have App.js which uses the TabBarIOS component to display my tabbed navigation at the bottom of the screen. When you touch a tab, the state updates and the relevant content is loaded and displayed:

App.js

import React, { Component } from 'react';
import { TabBarIOS, Platform, Image } from 'react-native';

import IconII from 'react-native-vector-icons/Ionicons';
import IconMCI from 'react-native-vector-icons/MaterialCommunityIcons';

import Colors from './Colors';
import RouterItem1 from './routers/RouterItem1';
import RouterItem2 from './routers/RouterItem2';
import RouterHome from './routers/RouterHome';
import Settings from './components/Settings';

class FooterNav extends Component {

  state = {
    selectedTab: 'home',
  };

  handleClick = (routeData) => {
    console.log('This has received data', routeData);
    this.setState({ selectedTab: routeData });
    console.log(this.state);
  }

  renderCurrentView() {
    switch (this.state.selectedTab) {
      case 'home':
        return (
          <RouterHome handleClick={this.handleClick} />
        );
      case 'item2':
        return (
          <RouterItem2 />
        );
      case 'item1':
        return (
          <RouterItem1 />
        );
      case 'settings':
        return (
          <Settings />
        );
      default:
        return false;
    }
  }

  render() {
    return (
      <TabBarIOS
        unselectedTintColor={Colors.third}     //Unselected labels
        unselectedItemTintColor={Colors.third} //Unselected icons
        tintColor={Colors.brandPrimary}        //Selected
        barTintColor={Colors.light}            //Bar background
      >
        <IconII.TabBarItem
          title="Home"
          iconName="ios-home-outline"
          selectedIconName="ios-home"
          selected={this.state.selectedTab === 'home'}
          receiveData={this.receiveData}
          onPress={() => {
            this.setState({
              selectedTab: 'home',
            });
          }}
        >
          {this.renderCurrentView()}
        </IconII.TabBarItem>
        <TabBarIOS.Item
          icon={require('./images/item2-icon-line@3x.png')}
          selectedIcon={require('./images/item2-icon-selected@3x.png')}
          title="item2"
          selected={this.state.selectedTab === 'item2'}
          onPress={() => {
            this.setState({
              selectedTab: 'item2',
            });
          }}
        >
          {this.renderCurrentView()}
        </TabBarIOS.Item>
        <IconMCI.TabBarItem
          title="item1"
          iconName="cookie"
          selectedIconName="cookie"
          selected={this.state.selectedTab === 'item1'}
          onPress={() => {
            this.setState({
              selectedTab: 'item1',
            });
          }}
        >
          {this.renderCurrentView()}
        </IconMCI.TabBarItem>
        <IconII.TabBarItem
          title="More"
          iconName="ios-more-outline"
          selectedIconName="ios-more"
          selected={this.state.selectedTab === 'settings'}
          onPress={() => {
            this.setState({
              selectedTab: 'settings',
            });
          }}
        >
          {this.renderCurrentView()}
        </IconII.TabBarItem>
      </TabBarIOS>
    );
  }
}

module.exports = FooterNav;

react-native-router-flux is a great plugin, once it pulls in a router the flow is exactly what I want it to be. The only problem I have is with the <RouterHome> module:

RouterHome.js

import React from 'react';
import { Scene, Router } from 'react-native-router-flux';

import styles from '../Styles';
import { content } from '../content.js';

import AnotherScene from '../components/pages/AnotherScene';
import Home from '../components/Home';

const RouterHomeComponent = () => {
  return (
    <Router
      sceneStyle={styles.sceneStyle}
      navigationBarStyle={styles.navBar}
      titleStyle={styles.navBarTitle}
      barButtonIconStyle={styles.barButtonIconStyle}
    >
      <Scene
        key="Home"
        component={Home}
        title={content.heading}
        hideNavBar
      />
      <Scene
        key="AnotherScene"
        component={AnotherScene}
        title='title'
        hideNavBar={false}
      />
    </Router>
  );
};

export default RouterHomeComponent;

The default view that is loaded is the <Home> module:

Home.js

import React, { Component } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Actions } from 'react-native-router-flux';

import styles from '../Styles';
import { content } from '../content.js';

class Home extends Component {

  displayItem1 = () => {
    this.props.handleClick('item1');
  }
  displayItem2 = () => {
    this.props.handleClick('item2');
  }
  displayAnotherScene() {
    Actions.AnotherScene();
  }

  render() {
    return (
      <View style={styles.viewWrapperHome}>

        <Text style={styles.heading}>{content.greeting}</Text>

        <TouchableOpacity onPress={this.displayItem1}>
          <Text>First item</Text>
        </TouchableOpacity>
        <TouchableOpacity onPress={this.displayItem2}>
          <Text>Second item</Text>
        </TouchableOpacity>
        <TouchableOpacity onPress={this.displayAnotherScene}>
          <Text>Another scene</Text>
        </TouchableOpacity>

      </View>
    );
  }
}

export default Home;

So what I expect to happen is that if the user clicks on the first two buttons displayed on the screen (First item/Second item), the prop will be passed back to App.js, the state will change and the scene will be updated. It basically is an alternative way of navigating without using the footer menu.

I know that this would work without using the react-native-router-flux module as I had it running before I added it in. The problem is that I really need it to handle the other pages from the <Home> module (many more to add).

Can anyone suggest a way I can pass back the props through the router back to my App.js?


Solution

  • Okay, so I actually figured this out - it turned out to totally be my fault; the props weren't getting passed to RouterHome and so they got lost either side. The new RouterHome looks like this:

    RouterHome.js

    import React from 'react';
    import { Scene, Router } from 'react-native-router-flux';
    
    import styles from '../Styles';
    import { content } from '../content.js';
    
    import AnotherScene from '../components/pages/AnotherScene';
    import Home from '../components/Home';
    
    const RouterHomeComponent = (props) => {      <---Didn't add props
      return (
        <Router
          sceneStyle={styles.sceneStyle}
          navigationBarStyle={styles.navBar}
          titleStyle={styles.navBarTitle}
          barButtonIconStyle={styles.barButtonIconStyle}
        >
          <Scene
            key="Home"
            component={Home}
            title={content.heading}
            hideNavBar
            handleClick={props.handleClick}     <---Didn't pass props
          />
          <Scene
            key="AnotherScene"
            component={AnotherScene}
            title='title'
            hideNavBar={false}
          />
        </Router>
      );
    };
    
    export default RouterHomeComponent;
    

    I've marked the two changes I made. Hopefully this will help someone! :)