0

I've used tab navigation of react-navigation. I need to call a loadData function in componentDidMount every time the tab is pressed. So I'm using addListener in it. But the problem is that it tooks too long to display the data. Sometimes it works seamlessly and sometimes it only shows "Loading Data..." all the time. Am I using the addListener correctly? Thanks in advance.

Home.js

state = {
  storageCheck: true
};

componentDidMount() {
    this._unsubscribe = this.props.navigation.addListener('willFocus', () => {
      this.loadData();
    });
}

componentWillUnmount() {
    this._unsubscribe.remove();
}

loadData = () => {
    this.setState({
        storageCheck: false
    })
}

render() {
if (this.state.storageCheck) {
  return <View>
    <Text>Loading Data...</Text>
  </View>
}
return (
    <View>
        <Text>Data</Text>
    </View>
)}

Tab navigation

const TabNavigator = createBottomTabNavigator({
  Home: {
    screen: Home
  },
  Profile: {
    screen: Profile,
    navigationOptions: ({ navigation }) => ({
      // title: 'Profile',
    })
  },
  Setting: {
    screen: Setting,
  }
},
  {
    defaultNavigationOptions: ({ navigation }) => ({
      tabBarIcon: ({ focused, tintColor }) => {
        const { routeName } = navigation.state;
        let iconName;
        if (routeName === 'Home') {
          iconName = 'home';
        } else if (routeName === 'Profile') {
          iconName = 'account-circle';
        } else if (routeName === 'Setting') {
          iconName = 'settings';
        }

        return <MaterialIcons name={iconName} size={28} color={tintColor} />;
      },
    })
  }
);

export default createAppContainer(TabNavigator);
Community
  • 1
  • 1
Amrita Stha
  • 2,973
  • 3
  • 25
  • 46

2 Answers2

1

In react-navigation v4.

You can use await-async functions.

state = {
  storageCheck: true,
  loader: true,
  someData: null
};

componentDidMount() {
    this._unsubscribe = this.props.navigation.addListener('willFocus', () => {
      this.loadData();
    });
}

componentWillUnmount() {
    this._unsubscribe.remove();
}

loadData = async() => {
    this.setState({
        someData: await AsyncStorage.getItem("SOME_KEY"),
        storageCheck: false,
        loader: false
    })
}

render() {
  return (
      <View>
       {this.state.someData ? (
        <Text>data is loaded</Text>
       ) : (
        <Text> loading ... </Text>
       )}
      </View>
  )
}

cheers!

0

This is a clear solution. I think you can use hooks and function component. I use a solution related to this

import React, { useState, useEffect } from "react";
import { 
    View,
    Text,
    ActivityIndicator
} from "react-native";
import { useIsFocused } from "@react-navigation/native";

const TestComp = () => {

    const [storageCheck, setStorageCheck] = useState(false);
    const [isLoaded, setIsLoaded] = useState(false);
    const isFocused = useIsFocused();

    useEffect(() => {
        const loadData = async() => {
            setStorageCheck(true);
            setIsLoaded(true);
        }
        loadData();
    }, [isFocused])


    return(
        <>
            {isLoaded ? (
                <View>
                    <Text>some data or texts..</Text>
                </View>
            ) : (
                <ActivityIndicator />
            )}
        </>
    )
}
export default TestComp;

cheers!

  • I've a older project so I cannot change it now. And I had used react navigation v4. – Amrita Stha May 16 '20 at 17:30
  • For v4 you should use NavigationEvents component. ` this.fetchData()} { // enter page component container } ` docs: [NavigationEvents](https://reactnavigation.org/docs/4.x/navigation-events/) – Eftal Yurtseven May 16 '20 at 17:32
  • I've tried navigationEvents as well. But I've to retrieve data from async storage, which make the layout flash for a milli-second before displaying the real data. So I moved to addListener. – Amrita Stha May 16 '20 at 17:41
  • 1
    Have you tried this? `loadData = async() => { this.setState({ key: await AsyncStorage.getItem("SOMEKEY"), loader: false }); }` In render func: `render(){ this.state.loader ? ( ) : ( ) }` – Eftal Yurtseven May 16 '20 at 17:45
  • 1
    tysm Eftal... you saved my day. Using await in the setState works great. Please include this line in the answer and I'll accept the answer. – Amrita Stha May 17 '20 at 07:54