I am calling forgotPassword api in the app and once its response comes from and state changes in reducer i get callback as i have useEffect in my component. I want to show user an alert that his password is reset successfully, but it shows only for 1 sec and goes away, i think whole view renders again. How can i make alert to staty until use taps on the button in alert.
useEffect(() => {
if (forgotPasswordData != null) {
Alert.alert('Success',forgotPasswordData.message, [{
text: 'OKAY',
onPress: () => {
dispatch({
type: authActions.RESET_FORGOT_PASSWORD_DATA,
});
console.log("Hello")
setEmail('');
setselectedAssociation(null);
setAssociationName('');
}
}]
);
}
}, [forgotPasswordData]);
When forgotPasswordData reset, useEffect will rerender again so the best option to alert the user is where you're getting a response.
You can create a callback function and define Alert in it and pass this callback to action and in Saga where you get a result, you can trigger this callback so It will Alert on view.
Related
Good evening everyone, I am facing a problem.
I am developing an app in react-native and I need that, every time a user sends the app in the background or in an inactive state, when he returns to the app I force him to go to a certain screen (Loading) where I perform certain checks (such as if he is a blocked user, deleted, etc ...).
I have now written the following function
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
getAttivita();
getBanner();
const appStateListener = AppState.addEventListener(
"change",
(nextAppState) => {
setAppState(nextAppState);
if (nextAppState === "active") {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: Routes.Loading }],
})
);
}
}
);
return () => {
appStateListener?.remove();
};
}, []);
I put this listener in the Screen Diary (which represents my home).
Now if from the screen Diary, I minimize the app, then I have no problems and everything works as it should.
However if I go to another screen and minimize the app, then I get the following error
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in Diary (at SceneView.tsx:122)
Then when I log back into the app I realize that the listener for the app status is still active (so it is as if the remove () had not worked) and in fact I am pushed back into my loading screen.
So I'm wondering, is it the listener that isn't actually being removed?
Or am I doing something wrong?
Thanks in advance to who will answer me .
I am new to react native and I have react native app for android and I am using Navigation 5 for navigating to the next page. The application workflow is loginScreen -> HomeScreen -> ExistingStockScreen -> ScanSkidBarcodeScreen -> ScanItemsScreen.
I am handling backbutton press with this code on ScanItemScreen.
navigation.addListener('beforeRemove', (e) => {
// Prevent default behavior of leaving the screen
e.preventDefault();
if (this.state.items[0].barCode !== "" && this.state.items[5].barCode !== "") {
Alert.alert(
'Error!',
'You can only scan six items at a time.',
[
{ text: "OK", style: 'cancel', onPress: () => { } },
]
);
}
else if (this.state.items[0].barCode !== "") {
Alert.alert(
'Attention!',
'You have unsaved items. Please click on UPDATE STATUS first and go back.',
[{ text: "OK", style: 'cancel', onPress: () => { } },
{
text: 'Go Back',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => navigation.dispatch(e.data.action),
},]
);
} else {
navigation.dispatch(e.data.action)
}
})
}
However navigation.dispatch(e.data.action) code is going to back screen but it logs out the user for some reason.
So I am thinking to use navigation.goBack() instead.
What's the difference between navigation.goBack() and navigation.dispatch(e.data.action) ?
The beforeRemove event is triggerred when the screen is being removed, which can happen because of various reasons (such as a reset or another action). While going back is one of the ways to trigger it, it's not the only way.
From the docs:
The user pressed back button on a screen in a stack
The user performed a swipe back gesture
Some action such as pop or reset was dispatched which removes the screen from the state
The object in e.data.action refers to the action which triggered that event. By dispatching that action again with navigation.dispatch(e.data.action), you continue the action after performing whatever check you needed e.g. prompting the user.
If you don't dispatch the event again and instead try to goBack():
It'll be incorrect behaviour - if a reset triggered the event, you should continue the reset (or whaetver triggered the event), not perform a different action entirely
It won't work anyway, because goBack will just trigger the event, so you'll be stuck in a loop of prompts
However navigation.dispatch(e.data.action) code is going to back screen but it logs out the user for some reason
React Navigation doesn't interact with your app state. If your user is being logged out on navigation, that's a bug in your code that you need to debug and fix.
I am using react-navigation(5.6.1) with redux-persist(6.0.0) on my react-native project. One of my reducer is persisted(profile). I added a focus event listener to run some functions when my profile screen in focus.
In those functions, the profile state will be used in some logic. On some other parts of the component, there will be other function that will be dispatching action which will update the profile state.
The issue now is whenever I update the profile state, each time the screen is in focus, I will always get the previous persisted data in the event listener. However, the component always render the latest persisted state. Anybody have any idea why this is happening? Below is the snippet of the event lister.
useFocusEffect(
React.useCallback(() => {
console.log(profile);
dispatch(showErrorDialog());
return () => {};
}
}, []),
If you do not give dependencies then useCallback will call the memorised function, not the updated one.
useFocusEffect(
React.useCallback(() => {
console.log(profile);
dispatch(showErrorDialog());
return () => {};
}
}, [profile]))
I'm using this package for implementing local push notification:
https://github.com/zo0r/react-native-push-notification
I'm using action button like this to show buttons in my notification along with a text and a title:
PushNotification.localNotification({
...
actions: '["Yes", "No"]'
})
I wanted to know how I can call a function when user clicks on of these actions and app becomes visible?
I've tried PushNotification.configure in my componentDidMount method in my home screen like this but nothing comes up in the console:
PushNotification.configure({
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log("NOTIFICATION:", notification);
if (notification.userInteraction) {
console.log("NOTIFICATION:");
}
// process the notification
}
});
I got it working.
In your App.js you need to set popInitialNotification to true. Something like this:
async componentDidMount() {
PushNotification.configure({
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log("NOTIFICATION:", notification.action);
},
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true
},
// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
*/
requestPermissions: true
});
}
notification.action will gibe you the label of the button clicked.
In your button/app active event you forgot to call to schedule the notification and actually set when it will arise, so you need to
PushNotification.localNotificationSchedule(details: Object)
Schedule it for now with the same id, then your notification will come up immediately.
See all options for scheduling here
import PushNotificationAndroid from 'react-native-push-notification'
(function() {
// Register all the valid actions for notifications here and add the action handler for each action
PushNotificationAndroid.registerNotificationActions(['Accept','Reject','Yes','No']);
DeviceEventEmitter.addListener('notificationActionReceived', function(action){
console.log ('Notification action received: ' + action);
const info = JSON.parse(action.dataJSON);
if (info.action == 'Accept') {
// Do work pertaining to Accept action here
} else if (info.action == 'Reject') {
// Do work pertaining to Reject action here
}
// Add all the required actions handlers
});
})();
DO NOT USE .configure() INSIDE A COMPONENT, EVEN App
If you do, notification handlers will not fire, because they are not loaded. Instead, use .configure() in the app's first file, usually index.js.
It's mentioned in the documentation.
Try to follow their example for implementation It will help you to setup in your project.
I am using react native v0.45.1.
How can I add to my application notification (no matter if the app is in the background or foreground) that the user can remove only after click an acknowledge button.
I don't want the user to swipe the notification aside without notice it.
how can it be done?
I am not sure https://github.com/wix/react-native-notifications will do what I need.
Edit
I want to have a notification that will act like:
'USB debugging connected
'Touch to disable USB debugging'
The notification can't be removed unless the user actively do something, in my case it will be 'click' on a button
after a lot of digging the solution I implemented was:
setting repeat interval for the notification.
for android:
repeatType: 'time',
repeatTime: timeSpan,
for iOS:
repeatType: 'minute',
when the user click the notification (decided its not the right approached to add actions - buttons - to notification):
PushNotification.configure({
onNotification: (notification) => {
console.log('NOTIFICATION:', notification);
const clicked = notification.userInteraction;
if (clicked) {
if (Platform.OS === 'ios') {
PushNotification.cancelLocalNotifications({ id: notification.data.id });
} else {
PushNotification.cancelLocalNotifications({ id: notification.id });
}
}
},
});
I am aware that this might not be the exact answer to this question. However,
I was looking for a similar solution earlier; how to remove notifications that hasn't been dismissed or opened by a user.
Sometimes the user might open the application / screen, without clicking on the notification. The notification will still be displayed in that case.
Using React Native with Expo, this is the solution I created for removing old notifications created using their Push Notification API.
import * as Notifications from "expo-notifications";
//...
// Remove notifications that exists for this conversation!
useEffect(() => {
Notifications.getPresentedNotificationsAsync().then(res => {
for (let k in res) {
if (
res[k].request.content.data &&
res[k].request.content.data.screen === "Conversations" &&
res[k].request.content.data.conversationId === conversationId
) {
Notifications.dismissNotificationAsync(res[k].request.identifier);
console.log("removed a notification for this conversation");
}
}
});
}, []);
By using the data sent to the Push Notification API, we can determine which notifications should be removed. in this case all notifications containing a conversationId matching the current value from the route are dismissed.