0

I have created a custom function component which has eventlistener from NetInfo for internet connection, which returns a bool value and method name. I wanted to call the method in every class component to check the internet connect and use the bool value to check the connection status.

Below is my code.

//function Component
import React, { PureComponent, useEffect, useState } from 'react';
import  NetInfo  from "@react-native-community/netinfo";


export default () => {
const [isInternetReachable, setIsInternetReachable] = useState(false)
const InternetChecker = () => {
    useEffect(() => {
        // Subscribe
        const unsubscribe = NetInfo.addEventListener((state) => {
            setIsInternetReachable(state.isInternetReachable);
            console.log("Connection type", state.type);
            console.log("Is internet Reachable?", isInternetReachable);
        });
        return () => {
            unsubscribe();
        };
    },[])
}

return [InternetChecker, isInternetReachable];

};

Class Component trying to access InternetChecker() method

class HomeScreen extends React.Component {

 render() {
 const { navigate } = this.props.navigation;
 const [InternetChecker, isInternetReachable] = InternetHanlder();
 // if (!isInternetReachable) {
 //     <NoNetworkSign /> 
 // }
 InternetChecker()
 if (isInternetReachable){
  console.log("Internet is Reachable");
 } else {
  console.log("No Internet Connection");
  
 }
 return (
  <SafeAreaView style={styles.container}>
    <View style={styles.container}>
    </View>
  </SafeAreaView>
 )
 };

When i try to access in the above way, i'm getting invalid hook call, Hooks can only be called from inside the body of a function component. How can we call it from a Class Component.

Any help appreciated.

Madhu
  • 869
  • 1
  • 17
  • 37
  • That is not a functional component. If anything it is a custom hook (A hook that is composed of other hooks). Components return jsx and are intended to be rendered. Your function doesn't return anything that can be rendered and you also call it as if it was a hook. You can't call hooks in a class component, also you can't call functions that call hooks in a class component. – trixn Jul 08 '20 at 07:54

3 Answers3

2

Add a name to the function

import React, { PureComponent, useEffect, useState } from 'react';
import  NetInfo  from "@react-native-community/netinfo";


export default ConnectivityChecker = () => {
const [isInternetReachable, setIsInternetReachable] = useState(false)
const InternetChecker = () => {
    useEffect(() => {
        // Subscribe
        const unsubscribe = NetInfo.addEventListener((state) => {
            setIsInternetReachable(state.isInternetReachable);
            console.log("Connection type", state.type);
            console.log("Is internet Reachable?", isInternetReachable);
        });
        return () => {
            unsubscribe();
        };
    },[])
}

return [InternetChecker, isInternetReachable];

};

where you want to use this function you should import it

Aymen
  • 248
  • 3
  • 15
1

First you should read the Hooks Rules, The first rule is do not call a react hook inside a class based Component, Thus simply update the HomeScreen component as a FC Component then try again it will surly Work.

And your custom hooks should be like this:

 export const useInternetStatus = () => {// I make a name to your hook is best in inspection and testing
const [isInternetReachable, setIsInternetReachable] = useState(false)
const InternetChecker = () => {
    useEffect(() => {
        // Subscribe
        const unsubscribe = NetInfo.addEventListener((state) => {
            setIsInternetReachable(state.isInternetReachable);
            console.log("Connection type", state.type);
            console.log("Is internet Reachable?", isInternetReachable);
        });
        return () => {
            unsubscribe();
        };
    },[isInternetReachable]) // in order to re-call the hooks whenever the netInfo status changed 
}

return [InternetChecker, isInternetReachable];

};
Hamza Hmem
  • 502
  • 5
  • 11
  • The naming convention for a hook is `useXYZ` so it should be `useInternetStatus` in that case. If you name it like this it will also be linted by the react hooks linting rule to warn you from missusing it. – trixn Jul 08 '20 at 08:03
0

The function you have shown is not a functional component as it doesn't return something that can be rendered. Also you are calling it like a hook. What you can do is to first fix the issues with your custom hook:

  1. It returns a hook (a function InternetChecker that calls useEffect). That is not needed. The hook should just call the useEffect itself, so it will subscribe to the NetInfo when mounting.

  2. The unsubscribe function should, as its name already suggests, unsubscribe from the NetInfo. Otherwise it will lead to memory leaks as your listener will be called even when your component already unmounted.

const useInternetStatus = () => {
    const [reachable, setReachable] = useState(false);
    
    useEffect(() => {
        const subscribe = state => setReachable(state.isInternetReachable); 

        NetInfo.addEventListener(subscribe);

        return () => NetInfo.removeEventListener(subscribe);
    },[]);

    return reachable;
};

Then you could re-write your HomeScreen component to be a functional component too which allows you to use the hook inside of it:

const HomeScreen = () => {
    const isInternetReachable = useInternetStatus();

    console.log(isInternetReachable);

    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.container}>
            </View>
        </SafeAreaView>
    );
};
trixn
  • 15,761
  • 2
  • 38
  • 55