React-native: NetInfo.isConnected.addEventListener only works in root componentDidMount

Created on 27 Feb 2018  路  9Comments  路  Source: facebook/react-native

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Android only

Environment:
OS: macOS Sierra 10.12.6
Node: 8.9.1
Yarn: 1.3.2
npm: 5.5.1
Watchman: 4.9.0
Xcode: Xcode 9.2 Build version 9C40b
Android Studio: 3.0 AI-171.4443003

Packages: (wanted => installed)
react: 16.2.0 => 16.2.0
react-native: 0.53.3 => 0.53.3

Steps to Reproduce

NetInfo.isConnected.addEventListener is not being registered unless on the root App.js component on componentDidMount.

(Write your steps here:)

  1. Under your App.js file, create an event listener for NetInfo. Note that this works just fine.
  2. Create a child component (class component in my case) that renders in App.js
  3. Under the child component in the componentDidMount or componentWillMount, create an event listener.
  4. The listener here on your child component will never be called.

Expected Behavior

Expected the same functionality for registering an event listener on NetInfo to be the same no matter where it is called in the app.

Actual Behavior

The function specified in NetInfo.isConnected.addEventListener never gets called on android unless it is in componentDidMount on App.js.

Reproducible Demo

Snippet of App.js containing the child component:

class App extends React.Component {

    //This works just fine if uncommented:
    // componentDidMount() {
    //     NetInfo.isConnected.addEventListener(
    //         'connectionChange',
    //         isConnected => {
    //             console.log('Connectedxc: ', isConnected);
    //         }
    //     );
    // }

    render() {
        return (
               <NetworkStatusProvider>
                     <Text>Some text</Text>
               </NetworkStatusProvider>
        );
    }
}

And in the NetworkStatusProvider:

import {NetInfo} from 'react-native';

class NetworkStatusProvider extends React.Component {

    componentDidMount() {
        NetInfo.isConnected.addEventListener(
            'connectionChange',
            (value) => {
                  console.log('Expected to see value logged: ', value);
            }
        );
    }

    render() {
        return this.props.children;
    }
}
Bug Locked

Most helpful comment

In my experience the NetInfo.isConnect returns offline for Android (when I'm online)

All 9 comments

Any Update?

Didn't find a specific fix for the issue, however our team found a workaround for it.

We are using redux-saga in order to manage the connectivity state of the app and using an event channel to monitor it:

// Forked off of our root saga
export function* networkConnectivitySaga() {
    const channel = yield call(createNetworkChangeChannel);
    try {
        while (true) {
            const connected = yield take(channel);
            // Dispatches an action to update our redux state
            yield put({ type: UPDATE_NETWORK_STATUS, connected });
        }
    } finally {
        if (yield cancelled()) {
            channel.close();
        }
    }
}

export function createNetworkChangeChannel() {
    return eventChannel(emitter => {
        NetInfo.isConnected.addEventListener('connectionChange', emitter);
        return () => { //Function to unsubscribe
            NetInfo.isConnected.removeEventListener(
                'connectionChange',
                emitter
            );
        };
    });
}

Not sure why this works and setting it up in a componentDidMount doesn't.

My workaround is to use NetInfo.isConnected.fetch. But not sure of its efficiency, though, since it gets called every time it mounts.

import {NetInfo, Platform} from 'react-native';

class NetworkStatusProvider extends React.Component {

    componentDidMount() {
        // Android hack for NetInfo addEventListener
        // not being detected on initial mount
        if (Platform.OS === 'android') {
            NetInfo.isConnected.fetch().then(isConnected => {
                console.log('Expected to see value logged: ', isConnected);
            })
        }
        NetInfo.isConnected.addEventListener(
            'connectionChange',
            (value) => {
                console.log('Expected to see value logged: ', value);
            }
        );
    }

    render() {
        return this.props.children;
    }
}

In my experience the NetInfo.isConnect returns offline for Android (when I'm online)

@ekimlinger Could you retest this issue in newest version of React Native (that would be v0.57.1 as of now)?

I'm using React Native v0.57.0 and it works fine on physical Android device (OnePlus6, Android v8.1.0). It detects offline/online changes for isConnected when changing Wifi On/Off and/or cellular On/Off.

I also tested this on iOS Simulator (iPhone 6, iOS 12) on macOS Mojave. The iOS simulator correctly interprets my Mac's Wifi switching off, but _doesn't pick up_ an event when WiFi is switched back on.

My component structure:

index.js ---v
     <App> ---v
          <Provider store> ---v
                <ThemeProvider> ---v
                        <RootContainer> ---V 
                               <SaveAreaView>
                                       <InternetConnectionCheckerContainer />  // subscribes to `NetInfo` events

This is how I set up my subscribes/unsubscribes inside <InternetConnectionCheckerContainer />:

```javascript
_handleFirstConnectivityChange = isConnected => {
isConnected ? this.props.internetConnected() : this.props.internetDisconnected()
}

componentDidMount () {
NetInfo.isConnected.addEventListener(
'connectionChange',
this._handleFirstConnectivityChange
)
}

componentWillUnmount () {
NetInfo.isConnected.removeEventListener(
'connectionChange',
this._handleFirstConnectivityChange
)
}
```

Still not working for me on react-native 0.57.3

My component structure:
` ---v

<App> ---v
   <Router> ---v
      <Menu> ---v   // subscribes to NetInfo and works
          <Provider> ---v  // subscribes to NetInfo and DOESN'T work
              <Component>  // subscribes to NetInfo and DOESN'T work

`

@gmaggio
how use this class as a separate component or within component. And how to implement to get network status?
Plz explain I'm a newbie to react-native (0.57.2)

  componentDidMount() {
    NetInfo.isConnected.addEventListener('change', this._handleConnectionChange);
  }

  componentWillUnmount() {
    NetInfo.isConnected.removeEventListener('change', this._handleConnectionChange);
  }

  _handleConnectionChange = (isConnected) => {
    this.props.dispatch(connectionState({ status: isConnected }));
  };

I am using as the example. When it change at the first time it working grate but when connectivity change again (online to offline or vice versa) its not working so event listener becomes dysfunctional. It just working once
I am toggling from wifi settings.

What I am wrong?

Heads up: we moved react-native-netinfo into its own repository, which should allow for making changes and fixes much faster. Please continue the discussion about this issue there: https://github.com/react-native-community/react-native-netinfo/issues/13

Was this page helpful?
0 / 5 - 0 ratings