TypeError: undefined is not an object (evaluating 'subscription[nativeEmitterSubscriptionKey]') when using animated spinner

Viewed 299

I am writing my application using Expo and React Native. I started using react-native-animated-loader, a wrapper around lottie-react-native, and I am having a strange issue. The thing is that I am occasionally getting some strange error. It's not reproducible all the time, but I am occasionally getting it. It looks like an eventual consistency or race condition issue.

TypeError: undefined is not an object (evaluating 'subscription[nativeEmitterSubscriptionKey]')

This error is located at:
    in NavigationContainer (at App.js:280)
    in Provider (at App.js:279)
    in Provider (at App.js:278)
    in Provider (at App.js:277)
    in Provider (at App.js:276)
    in Provider (at App.js:275)
    in Provider (at App.js:274)
    in Provider (at App.js:273)
    in RCTView (at View.js:34)
    in View (created by MenuProvider)
    in RCTView (at View.js:34)
    in View (created by MenuProvider)
    in MenuProvider (at App.js:272)
    in Provider (at App.js:271)
    in Provider (at App.js:270)
    in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
    in SafeAreaProvider (at App.js:269)
    in _default (created by ExpoRoot)
    in ExpoRoot (at renderApplication.js:45)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:106)
    in DevAppContainer (at AppContainer.js:121)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:132)
    in AppContainer (at renderApplication.js:39)
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:171:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:12:21 in ErrorUtils.setGlobalHandler$argument_0
at [native code]:null in flushedQueue
at [native code]:null in invokeCallbackAndReturnFlushedQueue

Here's the code I have:

import React, { useEffect } from 'react';
import {
    StyleSheet,
    View,
    Text
} from 'react-native';
import AnimatedLoader from "react-native-animated-loader";

const Loader = ({ visible }) => {

    return (
        <View style={styles.container}>
            <AnimatedLoader
                visible={visible}
                overlayColor="rgba(255,255,255,0.75)"
                source={require("../../assets/loader-strange.json")}
                animationStyle={styles.lottie}
                speed={1}
            >
                {/* <Text>Doing something...</Text> */}
            </AnimatedLoader>
        </View>
    )
};

const styles = StyleSheet.create({
    lottie: {
        width: 100,
        height: 100
    }
});

export default Loader;

The same happens if I use native lottie library:

import React, { useEffect } from 'react';
import {
    StyleSheet,
    View,
    Animated,
    Easing
} from 'react-native';
import LottieView from 'lottie-react-native';

const Loader = ({ visible }) => {
    const progress = new Animated.Value(0);

    useEffect(() => {
        Animated.timing(progress, {
            toValue: 1,
            duration: 5000,
            easing: Easing.linear,
        }).start();
    }, [])

    return (
        <View style={styles.container}>
            <LottieView
                source={require('../../assets/loader-strange.json')}
                progress={progress}
            />
        </View>
    )
};

const styles = StyleSheet.create({
    lottie: {
        width: 100,
        height: 100
    }
});

export default Loader;

I am then using it on one of my screens:

import React, { useEffect, useState, useContext, useRef } from 'react'
import {
    Text,
    FlatList,
    View,
    StyleSheet,
    RefreshControl
} from 'react-native';
...
import Loader from '../../components/Loader';

const InteractionsScreen = ({ navigation }) => {

    return (
        <View style={styles.container}>
            ...
            <Loader visible={true} />
            ...
        </View>
    );
}

const styles = StyleSheet.create({
    ...
});

export default InteractionsScreen;

In order to reproduce it, I have to refresh the app a few times, then I am getting this error. I tried googling this error and couldn't find anything meaningful.

image

1 Answers

In your stack trace, the line of code in your codebase is in App.js, on line 280. You haven't shown that file, but I can guess that it has to do with the push notifications code that was copied from this documentation page from Expo: https://docs.expo.dev/push-notifications/overview/.

return () => { 
  Notifications.removeNotificationSubscription(notificationListener.current);
  Notifications.removeNotificationSubscription(responseListener.current);
};

You want to only call those two functions when their argument is not undefined, so like this:

return () => { 
  if (notificationListener.current) {
    Notifications.removeNotificationSubscription(notificationListener.current);
  }

  if (responseListener.current) {
    Notifications.removeNotificationSubscription(responseListener.current);
  }
};

The same thing happened to me, and the code was working fine before, until it suddenly wasn't.

Related