How To Reload View Tap on TabNavigator in React Native

34.8k views Asked by At

I want to reload the tabNavigator when the user changse the tab each time. the lifecycle method of react native doesn't get called when user changes the tab. Then how can it be possible to reload tab in TabNavigator :

The below example have two Tabs : 1) Home 2)Events. Now I want to refresh the event Tab when user returns from the home tab.

EXPO LINK : Expo Tab Navigator

Code :

import React, {Component} from 'react';
import  {View, StyleSheet, Image, FlatList, ScrollView, Dimensions } from 'react-native';
import { Button, List, ListItem, Card  } from 'react-native-elements' // 0.15.0
//import { Constants } from 'expo';
import { TabNavigator, StackNavigator } from 'react-navigation'; // 1.0.0-beta.11

//image screen width and height defs
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;


export default class App extends Component {
  render() {
    //const { navigate } = this.props.navigation;
    return (
      <TabsNav  />
      )
  }
  }


class MyHomeScreen extends Component {
  render() {
    return (
      <View>
            <Image
              resizeMode="cover"
              style={{    width: windowWidth * .85,    height: windowHeight * 0.3}}
              source={{uri: 'http://www.ajaxlibrary.ca/sites/default/files/media/logo.png?s358127d1501607090'}}
            />
            <Button
              onPress={() => this.props.navigation.navigate('Notifications')}
              title="Go to notifications"
            />
      </View>

    );
  }
}

class AplEvents extends Component {
  static navigationOptions = {
    tabBarLabel: 'Events List',
    tabBarIcon: ({ tintColor }) => (
      <Image
        source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
        style={[styles.icon, {tintColor: tintColor}]}
      />
    ),
  };

    constructor(props) {
    super(props);

    this.state = {
      data: [],
      error: null,
    };
  }

  // when component mounts run the function fetch
  componentDidMount() {
    this.makeRemoteRequest();
  }

  makeRemoteRequest = () => {
    const url = `http://www.ajaxlibrary.ca/?q=calendar-test`;

    fetch(url)
      .then((res) => res.json())
      .then((res) => {
        this.setState({
          data: [...this.state.data, ...res.nodes],
          error: res.error || null,
        });
      })
      .catch(error => {
        this.setState( error );
      });
  };


  render() {
    const { navigate } = this.props.navigation;
    return (
         <List containerStyle={{ marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0 }}>
        <FlatList
          data={this.state.data}
          renderItem={({ item }) => (
            <ListItem
              //squareAvatar
              title={`${item.node.title}\n${item.node.Program_Location}`}
              subtitle={item.node.Next_Session}
              avatar={{ uri: item.node.Image }}
              containerStyle={{ borderBottomWidth: 0 }}
             // save params to pass to detailed events screen
              onPress={() => navigate('Details', {title: `${item.node.title}`,
                                                body: `${item.node.Body}`,
                                                date: `${item.node.Date}`,
                                                Next_Session: `${item.node.Next_Session}`,
                                                Program_Location: `${item.node.Program_Location}`,
                                                Nid: `${item.node.Nid}`,
                                                Image: `${item.node.Image}`,
                                                Run_Time: `${item.node.Run_Time}`})}
            />
          )}
          keyExtractor={item => item.node.Nid}
        />
        </List>
    );
  }
}

class EventDetails extends Component {
      static navigationOptions = {
    title: 'EventDetails'
  };
  render() {
    const { params } = this.props.navigation.state;

    let pic = {
      uri: `${params.Image}`
    };
    //const pic = { params.Image };
    return (

          <ScrollView>

              <Card
                title={params.title}
              >
                  <Image
                      resizeMode="cover"
                       style={{    width: windowWidth * .85,    height: windowHeight * 0.3}}
                      source={pic}
                  />

                  <Button style={{marginTop: 10}}
                      icon={{name: 'date-range'}}
                      backgroundColor='#03A9F4'
                      fontFamily='Lato'
                      buttonStyle={{borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}}
                      title='Add to Calendar'
                  />
                    <ListItem
                     title="Event Description"
                     subtitle={params.body}
                     hideChevron='true'
                    />
                    <ListItem
                     title="Date"
                     subtitle={`${params.Next_Session}\n Run Time - ${params.Run_Time}`}
                     hideChevron='true'
                    />
                    <ListItem
                     title="Location"
                     subtitle={params.Program_Location}
                     hideChevron='true'
                    />
              </Card>
          </ScrollView>
    );
  }
}


const styles = StyleSheet.create({
  icon: {
    width: 26,
    height: 26,
  },
});

const EventStack = StackNavigator({
    EventList: {
        screen: AplEvents,
          navigationOptions: {
            title: "APL Event Listing",
          }
    },
    Details: {
        screen: EventDetails,
    },
  TabsNav: { screen: MyHomeScreen}
  });

const TabsNav = TabNavigator({
  Home: {
    screen: MyHomeScreen,
        navigationOptions: {
            tabBarLabel: 'Home',
                 tabBarIcon: ({ tintColor }) => (
                <Image
                    source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
                    style={[styles.icon, {tintColor: tintColor}]}
                />
                ),
        },
  },
  EventList: {
    screen: EventStack,
            navigationOptions: {
            tabBarLabel: 'Events',
                 tabBarIcon: ({ tintColor }) => (
                <Image
                    source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
                    style={[styles.icon, {tintColor: tintColor}]}
                />
                ),
        },
  },
}, {
  tabBarOptions: {
    activeTintColor: '#e91e63',
  },
});
4

There are 4 answers

6
Val On BEST ANSWER

There's many long discussion about this from react-native issue 314, 486, 1335, and finally we got a way to handle this, after Sep 27, 2017, react-navigation version v1.0.0-beta.13:

New Features

Accept a tabBarOnPress param (#1335) - @cooperka

So here we go,

Usage:

const MyTabs = TabNavigator({
  ...
}, {
  tabBarComponent: TabBarBottom /* or TabBarTop */,
  tabBarPosition: 'bottom' /* or 'top' */,
  navigationOptions: ({ navigation }) => ({
    tabBarOnPress: (scene, jumpToIndex) => {
      console.log('onPress:', scene.route);
      jumpToIndex(scene.index);
    },
  }),
});
1
aybars On

look at this link. My problem is solving thanks to this.

<Tabs.Navigator
    initialRouteName="Home"
    tabBar={(props) => (
       <TabBar {...props} />
    )}>
    <Tabs.Screen
      name="Home"
      component={HomeView}
      options={{ unmountOnBlur: true }}
      listeners={({ navigation }) => ({
        blur: () => navigation.setParams({ screen: undefined }),
      })}
    />
  </Tabs.Navigator>

https://github.com/react-navigation/react-navigation/issues/6915#issuecomment-692761324

3
evanmcd On

I wasn't able to get this to work, and after checking the React Navigation documentation, found this, which seems to suggest that later versions (I'm using 1.0.0-beta.27) changed the method signature to a single object:

tabBarOnPress Callback to handle tap events; the argument is an object containing:

the previousScene: { route, index } which is the scene we are leaving

the scene: { route, index } that was tapped

the jumpToIndex method that can perform the navigation for you

https://reactnavigation.org/docs/en/tab-navigator.html#tabbaronpress

Given that, and the code from beausmith here, I put this together.

navigationOptions: ({ navigation }) => ({
    tabBarOnPress: (args) => {
        if (args.scene.focused) { // if tab currently focused tab
        if (args.scene.route.index !== 0) { // if not on first screen of the StackNavigator in focused tab.
            navigation.dispatch(NavigationActions.reset({
            index: 0,
            actions: [
                NavigationActions.navigate({ routeName: args.scene.route.routes[0].routeName }) // go to first screen of the StackNavigator
            ]
            }))
        }
        } else {
            args.jumpToIndex(args.scene.index) // go to another tab (the default behavior)
        }
    }
})

Note that you'll need to import NavigationActions from react-navigation for this to work.

Hope this helps somebody :)

2
Suyash Vashishtha On

React Native Tab Navigation has an option prop as unmountOnBlur set it to true and it will reload the tab screens every time you click on tabs.

<Tab.Screen name={"Profile"} component={ProfileScreen} options={{unmountOnBlur: true}} />

Doc/Ref - RN Bottom tab Navigator docs

.

Update - There is a hook called as useIsFocused in '@react-navigation/native'. Use this with useEffect to re-render the screen every time it is focused or used .

import { useIsFocused } from '@react-navigation/native';

const isFocused = useIsFocused();

useEffect(() => { yourApiCall(); }, [isFocused])