So I want to drop the user into a specific navigator scene when they tap an incoming push notification. The "scene" and the "id" used are passed in the notification payload as JSON.
But I have no idea what to do with these values inside the
PushNotificationIOS.addEventListener('notification', this._onNotification.bind(this));
"notification" event.
Obviously the app appears when tapping the notification, but how to I fire a function once it does?
Thanks!!
In your topmost component, the one registered in your index.ios.js, in the componentDidMount method, you can add your listener and get the data from the notification:
export default class App extends Component {
componentDidMount() {
PushNotificationIOS.addEventListener('notification', this._onNotification.bind(this));
if (notification) {
const data = notification.getData();
if (data) {
// do your thing
}
}
}
}
Another solution would be to pass a url, and to implement the following code, also in your topmost component's componentDidMount method:
Linking.getInitialURL().then(url => {
if (!url) {
return null;
}
// do something to decide which component to load
navigator.push({
component: YourComponent,
passProps: {
// your props
},
});
return null;
}).catch(() => null);
Related
//root dart file
FirebaseMessaging.onBackgroundMessage(_backgroundMessageHandler);
await NotificationService.instance.initializeNotifications();
Future<void> _backgroundMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
}
//In, NotificationService file, I have initialized
AwesomeNotification(awesome_notification package),and have
//This handles notification actions
AwesomeNotifications().actionStream.listen((notification) async {
print(notification.payload);
if (notification.payload != null) {
final payload = notification.payload!;
if (payload['type'] == 'vaccine-records') {
_appRouter.root.innerRouterOf(DashboardRouter.name)
?..innerRouterOf<TabsRouter>(DashboardRoute.name)?.setActiveIndex(2)
..navigate(
VaccineRecordsRouter(
petId: int.parse(payload['id']!),
petType: int.parse(payload['pet_type']!),
petName: notification.title,
),
);
}
}
});
//this listens to new notification from Firebase cloud messaging
FirebaseMessaging.onMessage.listen((message) async {
print(message.data);
if (message.data.isNotEmpty) {
await AwesomeNotifications().createNotificationFromJsonData(message.data);
} else {
print('here');
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: 0,
channelKey: 'basic_channel',
title: message.notification?.title,
body: message.notification?.body,
showWhen: true,
displayOnForeground: true,
displayOnBackground: true,
),
);
}
});
}
When I tap on the notification, it takes me to homepage of my app. I want it to
navigate me to some other screen.When the app is in the foreground and I receive the
notification, it takes me to the desired page. But when the app is in the background
and the notification is received, it takes me to the homepage.How is this happening
since the both time i get AwesomeNotifications().actionStream.listen((notification)
async {} to execute?
I would suggest you use Firebase dynamic links to send the users to specific page based on the payload of notification.
In your current case,
onMessage function is triggered only when the app is in foreground.
Notifications must be handled for 3 states.
When app is in foreground
When app is in background
When app is terminated
Use the following :
//when app is terminated
FirebaseMessaging.instance.getInitialMessage().then((value) {
if (value != null) {
_onNotificationMessage(context, value); // custom function to handle notification
}
});
//when app is in foreground
FirebaseMessaging.onMessage.listen((message) {
_onProcessMessage(context, message); // custom function to handle notification
});
//when app is in background
FirebaseMessaging.onMessageOpenedApp.listen((message) {
_onNotificationMessage(context, message); // custom function to handle notification
});
}
I want to connect firebase stuff. What I'm trying in my news feed is when I press addTofavourite its name should go to firebase. So in my code for fetch, I used componentDidMount and for sending too there is componentDidMount. I have no idea how to connect them.
This is what I tried, but it's not working.
componentDidMount() {
firebase.auth().signInWithEmailAndPassword
("web#imandy.ie", "123456")
//////////////////////////////////////
this.fetchNews();
}
for fetching news
componentDidMount() {
this.fetchNews();
}
for firebase thing
componentDidMount() {
firebase.auth().signInWithEmailAndPassword("web#imandy.ie", "123456" )
}
Please try like this
componentDidMount = async () => {
const { user } = await firebase.auth().signInWithEmailAndPassword("web#imandy.ie", "123456");
// If you want to use user detail, write code here
// ...
this.fetchNews();
}
you have to call this function in componentWillReciveProps(){} or componentDidUpdate(){}
I'm a bit confused over the firebase function onAuthStateChanged().
componentDidMount() {
fbAuth.onAuthStateChanged(function(user) {
if (user) { //THIS TRIGGERS BOTH AT LOGIN AND REGISTRATION
console.log("LOGGED IN");
} else {
//TRIGGERS WHEN LOGGING OUT; NOT WHEN FAILING TO LOGIN!
console.log("LOGGED OUT");
}
});
}
I thought that the if(user) block triggered when the user has logged in, but the console.log is also triggered when a new account is created. How do I make a conditional that only triggers at login (and not by creating a new account?)
onAuthStateChanged(nextOrObserver, error, completed) returns function()
returns a listener function
Therefore you need to listen it when the component is mounted and unlisten when the component is unmounted
You need to make a separate Component if you want to listen specifically for Login
Login.js // Or whatever your login component is
componentDidMount() {
// Bind the variable to the instance of the class.
this.authFirebaseListener = firebase.auth().onAuthStateChanged((user) => {
this.setState({
loading: false, // For the loader maybe
user, // User Details
isAuth: true
});
});
}
componentWillUnmount() {
this.authFirebaseListener && this.authFirebaseListener() // Unlisten it by calling it as a function
}
I want to use only React, React Redux, React Router and Redux Thunk.
I want to navigate to a dashboard page when a successful user creation action is dispatched. Here is my async action creator,
export function createUser() {
return dispatch => {
dispatch(creatingUser());
return axios.post('/api/users').then(() => {
// how to navigate to dashboard after this action is dispatched?
dispatch(createdUser());
});
};
}
Can you show me exactly where is the place I should naviage programmatically?
Initially looking, I would hope that "createdUser" returns a promise (like #idbehold asked previously)
in a nutshell, something like this.
// make sure your function createdUser returns a promise
function createdUser() {
return new Promise((resolve, reject) => {
//simulate some api request
setTimeout( () =>{
// api resolves. in the .then() do:
resolve()
}, 4000)
})
}
// the dispatch will forward resolution of the promise ahead into the
// .then.. then you can redirect.
dispatch(createdUser()).then( ()=> {
console.log("NAVIGATING AWAY")
//browserHistory.push('/some/path')
//assuming you are importing browserHistory
})
I hope I was helpful, if not :-( , perhaps I didn't fully understand what your need is/was. Let me know, and I'll try to help further.
I'm trying to build a simple app to view photos posted from nasa's picture of the day service (https://api.nasa.gov/api.html#apod). Currently watching for keypresses, and then changing the date (and asynchronously the picture) based on the keypress being an arrow left, up, right, or down. These would correspondingly change the date represented by a week or a day (imagine moving across a calendar one square at a time).
What I'm having trouble with is this: I've created an async action creator to fetch the next potential date - however I need to know the current state of the application and the keypress to retrieve the new date. Is there a way to encapsulate this into the action creator? Or should I put the application state where the exported action creator is called in the application so I can keep my action creator unaware of the state of the application? I've tried to do this by binding the keydown function in componentDidMount for the top level Component, but the binding to the application store doesn't seem to reflect the changes that happen in the reducer.
The async logic relying on redux-thunk middleware and q:
// This function needs to know the current state of the application
// I don't seem to be able to pass in a valid representation of the current state
function goGetAPIUrl(date) {
...
}
function getAsync(date) {
return function (dispatch) {
return goGetAPIUrl(date).then(
val => dispatch(gotURL(val)),
error => dispatch(apologize(error))
);
};
}
export default function eventuallyGetAsync(event, date) {
if(event.which == 37...) {
return getAsync(date);
} else {
return {
type: "NOACTION"
}
}
}
Here's the top level binding to the gridAppState, and other stuff that happens at top level that may be relevant that I don't quite understand.
class App extends React.Component {
componentDidMount() {
const { gridAppState, actions } = this.props;
document.addEventListener("keydown", function() {
actions.eventuallyGetAsync(event, gridAppState.date);
});
}
render() {
const { gridAppState, actions } = this.props;
return (
<GridApp gridAppState={gridAppState} actions={actions} />
);
}
}
App.propTypes = {
actions: PropTypes.object.isRequired,
gridAppState: PropTypes.object.isRequired
};
function mapStateToProps(state) {
return {
gridAppState: state.gridAppState
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(GridActions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
I've validated that the correctly modified date object is getting to the reducer - however the gridAppState seems stuck at my initial date that is loaded.
What is the right way to approach async logic in redux that relies on attaching event handlers and current application state? Is there a right way to do all three?
You should handle the event in your component and call the correct action depending on the key pressed.
So when you dispatch an async action you can do something like
export default function getNextPhoto(currentDate) {
return (dispatch) => {
const newDate = calculateNewDate(currentDate);
dispatch(requestNewPhoto(newDate));
return photosService.getPhotoOfDate(newDate)
.then((response) => {
dispatch(newPhotoReceived(response.photoURL);
});
};
}
You should handle the keypress event on the component and just dispatch your action when you know you need to fetch a new photo.
Your App would look like
class App extends React.Component {
componentDidMount() {
const { gridAppState, actions } = this.props;
document.addEventListener("keydown", function() {
if (event.which == 37) {
actions.getNextPhoto(gridAppState.date);
} else if (...) {
actions.getPrevPhoto(gridAppState.date);
}
// etc
});
}
}
By the way you re still missing your reducers that update your state in the Redux Store.