Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-native-navigation Change state from another tabnavigator

I'm using react-navigation / TabNavigator, is there a way to change the state of a tab from another tab without using Redux or mobx?

like image 251
rayashi Avatar asked Jun 29 '26 10:06

rayashi


1 Answers

Yes you can. It is a little complicated, a little hacky and probably has some side-effects but in theory you can do it. I have created a working example snack here.

In react-navigation you can set parameters for other screens using route's key.

When dispatching SetParams, the router will produce a new state that has changed the params of a particular route, as identified by the key

  • params - object - required - New params to be merged into existing route params
  • key - string - required - Route key that should get the new params

Example

import { NavigationActions } from 'react-navigation'

const setParamsAction = NavigationActions.setParams({
  params: { title: 'Hello' },
  key: 'screen-123',
})
this.props.navigation.dispatch(setParamsAction)

For this to work you need to know key prop for the screen you want to pass parameter. Now this is the place we get messy. We can combine onNavigationStateChange and screenProps props to get the current stacks keys and then pass them as a property to the screen we are currently in.

Important Note: Because onNavigationStateChange is not fired when the app first launched this.state.keys will be an empty array. Because of that you need to do a initial navigate action.

Example

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      keys: []
    };
  }
  onNavigationChange = (prevState, currentState) => {
    this.setState({
      keys: currentState.routes
    });
  }
  render() {
    return(
      <Navigation
        onNavigationStateChange={this.onNavigationChange}
        screenProps={{keys: this.state.keys}}
      />
    );
  }
}

And now we can use keys prop to get the key of the screen we need and then we can pass the required parameter.

class Tab1 extends Component {
  onTextPress = () => {
    if(this.props.screenProps.keys.length > 0) {
      const Tab2Key = this.props.screenProps.keys.find((key) => (key.routeName === 'Tab2')).key;
      const setParamsAction = NavigationActions.setParams({
        params: { title: 'Some Value From Tab1' },
        key: Tab2Key,
      });
      this.props.navigation.dispatch(setParamsAction);
    }
  }
  render() {
    const { params } = this.props.navigation.state;
    return(
      <View style={styles.container}>
        <Text style={styles.paragraph} onPress={this.onTextPress}>{`I'm Tab1 Component`}</Text>
      </View>
    )
  }
}

class Tab2 extends Component {
  render() {
    const { params } = this.props.navigation.state;
    return(
      <View style={styles.container}>
        <Text style={styles.paragraph}>{`I'm Tab2 Component`}</Text>
        <Text style={styles.paragraph}>{ params ? params.title : 'no-params-yet'}</Text>
      </View>
    )
  }
}

Now that you can get new parameter from the navigation, you can use it as is in your screen or you can update your state in componentWillReceiveProps.

componentWillReceiveProps(nextProps) {
  const { params } = nextProps.navigation.state;
  if(this.props.navigation.state.params && params &&  this.props.navigation.state.params.title !== params.title) {
    this.setState({ myStateTitle: params.title});
  }
}

UPDATE

Now react-navigation supports listeners which you can use to detect focus or blur state of screen.

addListener - Subscribe to updates to navigation lifecycle

React Navigation emits events to screen components that subscribe to them:

  • willBlur - the screen will be unfocused
  • willFocus - the screen will focus
  • didFocus - the screen focused (if there was a transition, the transition completed)
  • didBlur - the screen unfocused (if there was a transition, the transition completed)

Example from the docs

const didBlurSubscription = this.props.navigation.addListener(
  'didBlur',
  payload => {
    console.debug('didBlur', payload);
  }
);
// Remove the listener when you are done
didBlurSubscription.remove();

// Payload
{
  action: { type: 'Navigation/COMPLETE_TRANSITION', key: 'StackRouterRoot' },
  context: 'id-1518521010538-2:Navigation/COMPLETE_TRANSITION_Root',
  lastState: undefined,
  state: undefined,
  type: 'didBlur',
};
like image 191
bennygenel Avatar answered Jul 02 '26 08:07

bennygenel