nebsi04
nebsi04

Reputation: 51

React Native + Onesignal / navigation or popup with push notification

I am using React Native, react-native-onesignal, and react-navigation. When my action button in the push notification is pressed, I am trying to navigate to a screen or just show a modal pop up that I can render another screen in.

I cannot get this to work. I keep getting errors like: "Cannot read property 'navigation' of undefined" or "this.setState is not a function"

I have tried to navigate to another screen and I have tried to set a visible state to true of a modal popup and failed to succeed at both. So, I think I may be misunderstanding something all together with my approach.

Here is some code to help everyone further understand the problem:

note: I am aware that I don't have a 'navigation' prop reference, but I am not sure how to access it. I thought is was available to me from the child element in my router.js file.

additional note: I think the problem is because I am trying to navigate somewhere or render a popup from the 'onOpened(openResult)' handler function. Not sure how to include this in the actual render part of the component if that is what is needed.

THIS IS THE APP CONTAINER (index.js):

import React, { Component } from 'react';
import { Text, Modal, View, Alert } from 'react-native';
import OneSignal from 'react-native-onesignal';
import { Root } from './config/router';

class App extends Component {
constructor(props) {
    super(props);
    this.state = { modalVisible: false };
    this.setModalVisible = this.setModalVisible.bind(this);
}

componentWillMount() { 
    OneSignal.addEventListener('received', this.onReceived);
    OneSignal.addEventListener('opened', this.onOpened);
    OneSignal.addEventListener('registered', this.onRegistered);
    OneSignal.addEventListener('ids', this.onIds);
}

componentDidMount() {
    FingerprintScanner
    .isSensorAvailable()
    .catch(error => this.setState({ errorMessage: error.message }));
}

componentWillUnmount() {
    OneSignal.removeEventListener('received', this.onReceived);
    OneSignal.removeEventListener('opened', this.onOpened);
    OneSignal.removeEventListener('registered', this.onRegistered);
    OneSignal.removeEventListener('ids', this.onIds);
}

onReceived(notification) {
    console.log('Notification received: ', notification);
}

onOpened(openResult) {        
    console.log('Message: ', openResult.notification.payload.body);
    console.log('Data: ', openResult.notification.payload.additionalData);
    console.log('isActive: ', openResult.notification.isAppInFocus);
    console.log('openResult: ', openResult);
    if (openResult.action.actionID === 'fingerprint_id') {           
        console.log('fingerprint_id: ', 'clicked');
        //this.props.navigation.navigate('tbdScreen');
        //or
        //this.setModalVisible(true)
    }
}

onRegistered(notifData) {
    console.log('Device had been registered for push notifications!', notifData);
}

onIds(device) {
console.log('userId: ', device.userId);
}

setModalVisible(visible) {
    this.setState({ modalVisible: visible });
}    

render() {        
    return (
             <Root>
                <View>
                     <Modal
                         animationType={"slide"}
                         transparent={false}
                         visible={this.state.modalVisible}                    
                     >
                         <View>
                             <Text>this is the modal!</Text>
                         </View>
                     </Modal>
                </View>
             </Root>
           );

}
}

export default App;

THIS IS MY ROUTER FILE (router.js):

import React from 'react';
import { TabNavigator, StackNavigator } from 'react-navigation';

import WelcomeScreen from '../screens/WelcomeScreen';
import AuthScreen from '../screens/AuthScreen';
import HomeScreen from '../screens/HomeScreen';
import SettingsScreen from '../screens/SettingsScreen';
import TBDScreen from '../screens/TBDScreen';

export const HomeStack = StackNavigator({
    home: {
        screen: HomeScreen
    },
    settings: {
    screen: SettingsScreen,
    navigationOptions: {
        title: 'Settings'
    }
}
}
);

export const Tabs = TabNavigator({
    welcome: {
        screen: WelcomeScreen,
        navigationOptions: {            
            TabBarLabel: 'Welcome'
        }
    },
    auth: {
        screen: AuthScreen,
        navigationOptions: {            
            TabBarLabel: 'Auth'
        }
    },
    home: {
        screen: HomeStack,
        navigationOptions: {            
            TabBarLabel: 'HomeScreen'
        }
    }
},
{
    tabBarPosition: 'bottom'
});

export const Root = StackNavigator({
    Tabs: {
        screen: Tabs,
   },    
    tbdScreen: {
        screen: TBDScreen,
    }
},
{
    mode: 'modal',
    headerMode: 'none',
});

I have also been looking into using Redux with my React Navigation to persist the navigation state. Maybe this is what I need to do to access the navigation actions of the router.js file from the App component in the index.js file?

Anyway, much thanks in advance as I have been stuck on this for a while and I'm looking to learn from this problem.

Upvotes: 3

Views: 2969

Answers (2)

Bishnu Pada Chanda
Bishnu Pada Chanda

Reputation: 5416

Just do as follows:

componentWillMount() { 
    this.onReceived = this.onReceived.bind(this);
    this.onOpened = this.onOpened.bind(this);
    this.onRegistered = this.onRegistered.bind(this);
    this.onIds = this.onIds.bind(this);
    OneSignal.addEventListener('received', this.onReceived);
    OneSignal.addEventListener('opened', this.onOpened);
    OneSignal.addEventListener('registered', this.onRegistered);
    OneSignal.addEventListener('ids', this.onIds);
}


Upvotes: 0

razbard
razbard

Reputation: 183

Your onOpened function does not have the right scope because it is being called within OneSignal's addEventListener function so you have to bind "this" as below.

Change OneSignal.addEventListener('opened', this.onOpened);

to

OneSignal.addEventListener('opened', this.onOpened.bind(this));

And you will have this.props.navigation.navigate available inside the onOpened function.

Upvotes: 2

Related Questions