0

Ok, I give up. This must be so basic, no one documented it anywhere.

I have 3 basic components, all clickable from a basic with 3 Tab Items.

How can I emulate a user clicking one of the tab items? For example, pretend component1 has an action - that when successful - directs the user to component2 (as if they clicked it from the tabitem)

I can provide some code, otherwise just assume I have a basic tutorial app. I feel like what I'm looking for is essentially a hyper-link.

kevando
  • 275
  • 4
  • 17
  • Are you trying to navigate to another component when the action fires? When you call an onPress function, you basically pass it another function with your functionality, so I'm assuming you can just disregard the onPress and call the function directly after whatever emulation you want to occur. – Nader Dabit Nov 23 '15 at 15:19
  • Thanks @NaderDabit Yeah I'm looking for exactly that. I feel like an idiot but I don't know how to "call the function directly after whatever emulation you want to occur." I've tried Component2.render() etc. Nothing seems to work. – kevando Nov 24 '15 at 01:18

1 Answers1

0

You should probably see the react components as a tree and you can pass the function that you want to trigger from parents to children as props.

Say you have a Tab component -

const Tab = React.createClass({

  onPressButton(){
    triggeredFunction();
  },

  render() {
    return (
      <Button onPress={this.onPressButton}>
        <Text>Press Me!</Text>
      </Button>
    );
  },

});

You can simply call triggeredFunction() (or this.onPressButton from within the component) if you want to emulate the touch.

If you are trying to trigger the function from a parent component, you should probably have the triggered function in the parent and pass it as prop -

const Tab = React.createClass({

propTypes: {
  onPressButton: React.PropTypes.func,
  tabNumber: React.PropTypes.number,
  tabText: React.PropTypes.string,
},

triggerTheTriggerToTrigger() {
  // This will trigger the triggeredFunction in the page component and pass in the tab number
  // Remember that onPressButton={this.triggeredFunction}
  // So you are calling this.triggeredFunction(tabNumber) in the parent page component
  this.props.onPressButton(this.props.tabNumber);
},

  render() {
    return (
      <Button onPress={this.triggerTheTriggerToTrigger}>
        <Text>{this.props.tabText}</Text>
      </Button>
    );
  },

});

Then in your main component

const Page = React.createClass({

getInitialState() {
 return {
  currentTab: 1,
 };
},

triggeredFunction(tabNum) {
 // This function is setting the state of the page component to be equal to that passed from the tab
 // So when the tab is touched it will trigger the page to change to that number.
 this.setState({
  currentTab: tabNum,
 });
},

// main component render:
  render() {

   let content;

   // We are setting the page 'content' from here
   // Choosing the content from the currentTab state
   switch (this.state.currentTab) {
    case 1:
     content = <Text>This is the content for tab 1</Text>
    break
    case 2:
     content = <Text>Tab 2 has a slightly different message</Text>
    break
    case 3:
     content = <Text>Tab 3 is slightly different too</Text>
    break
   }

    return (
    <View className="page">
     <View className="toptabs">
      <Tab onPressButton={this.triggeredFunction} tabText="Button 1" tabNumber={1} />
      <Tab onPressButton={this.triggeredFunction} tabText="Button 2" tabNumber={2} />
      <Tab onPressButton={this.triggeredFunction} tabText="Button 3" tabNumber={3} />
     </View>
     <View className="pageContent">
      {content}
     </View>
    </View>
    );
 },
});

Then you can call this.triggeredFunction() from the main component instead. I hope this makes sense.

I haven't tested this code, so it might need some tweaking, but hopefully it shows you the logic behind it.

Also, I'm using a switch statement here to make what is going on obvious. I wouldn't probably use this method in a real app (not that it's particularly awful). You could also load in other components and conditionally load them based on the currentTab state. You could create an array of contents and have - let content = contents[this.state.currentTab];

You can also achieve this through other means. I'm using flux in my app, which consists of store that you update. These stores then propagate the view with data. This means you get more of a global setting. If you were using flux then you would basically set the page state (i.e. tabNumber) from flux.

So, in your tab you could set onPressButton to - this.flux.action.updateTab(this.props.tabNumber); This would update the global store to set what tabNumber you are on (i.e. you are not just setting currentTab on the page component anymore)

And in your page you could get your currentTab state from something like - currentTab: this.flux.store.tabStore.getCurrentTab() So the store updates your page component when it updates.

But this is a more complicated implementation than you are using and it's beyond the scope of what we are discussing here. Don't worry if that part is confusing, but it may be helpful to consider it if you are building something larger in the future (imagine 10 different app 'pages' with tab sections for different things, suddenly you want a storage place where you can control the state of them, rather than in each set of components).

Dan Munday
  • 381
  • 2
  • 9
  • this makes sense, but I'm still not seeing how to actually render the component. I see this is how to do the onPress to a function, but what should be in the TriggeredFunction() that actually switches the display to the other component. – kevando Nov 29 '15 at 03:11
  • I'm having a bit of a nightmare trying to write a full reply in this comment box, so I'll add to my solution. – Dan Munday Nov 30 '15 at 10:05
  • Ok, I update the above solution so that it contains a full implementation of how you would code the tabs in and trigger a function on the parent page. Give me a +1 if you found it helpful. – Dan Munday Nov 30 '15 at 11:29