react-native how to remove persistence on firebase snapshot - react-native

I am little confused.
I am listening to firebase snapshot with sample code below
unsubscribe = firebase
.firestore()
.collection('collection')
.doc(id)
.onSnapshot(
function(doc) {
// other code
},
);
This will listen to the collection if there's new item for the specific id.
Then, closing the app will unsubscribe to the snapshot
useEffect(() => {
return () => {
if (unsubscribe) {
unsubscribe()
}
}
}, []);
It is working fine.
However, given the scenario.
If the snapshot triggered (eg. { value: 1 }) and then I closed the app.
Removed the value on the firebase for the specific id. (meaning the id should not received the item)
Re-open the app
I still get the previous value which is { value: 1} and then get the newest value which is undefined (since i removed the value)
Is the value persists on the app? How can I remove this one upon re-opening of the app?
Thanks!

From this answer:
There is now a feature in the API for clearing persistence. It is not recommended for anything but tests, but you can use
firebase.firestore().clearPersistence().catch(error => {
console.error('Could not enable persistence:', error.code);
})
It must run before the Firestore database is used.

Related

react-native-iap I have problem with successfully make a subscription payment

Have anyone successfully implemented in app subscriptions with react-native-iap in an app.
I have tried to implement it but still very unstable. Can't rely that the subscription payments work every time. Sometimes the pay dialog won't show, sometimes it won't continue, and so on. Its a problem on both android and iOS.
Short explanation on how I have implemented it:
When clicked on pay button after the user has selected the plan, for ex. monthly.
await requestSubscription({
sku: subscription.productId,
...(offerToken && { subscriptionOffers: [{sku: subscription.productId, offerToken}]}),
})
Then I have to listeners, currentPurchaseError and currentPurchase that is returned as a hook from the rniap library.
React.useEffect(() => {
const onError = async () => {
// Do something on error from rniap.
}
if (currentPurchaseError) {
onError()
}
}, [currentPurchaseError])
And
React.useEffect(() => {
const checkCurrentPurchase = async () => {
// Do something, this should trigger when a purchase is successful.
}
if (currentPurchase) {
checkCurrentPurchase()
}
}, [currentPurchase, finishTransaction])
My receipt validation is happening on our own backend and its worth mentioning that everything there is working.
As I asked, has anyone implemented this successfully. If so, how?
Or is it worth thinking of changing to like revenue cat?
rniap's documentation and example code is really small and right now I need some help.
/Alexander
I have tried to get a successful payment within iOS sandbox but with no luck.

How can I obtain a reference to the URL that was used to open my app with a link in iOS

I have a problem with the situation where my React Native Expo app is running in the background / inactive modus and the app is brought back to the foreground / active mode as a result of the user opening a deep link to my app from the mobile browser.
When this situation occurs, my app needs to get a reference to the deep link in order to show the expected content to the user. The problem is that Linking.getInitialURL() always returns the link that was used to open the app from cold start and not the link that was used to bring the app back to foreground / active modus.
Advice on how to fix this problem would be greatly appreciated.
Found it out by myself :-)
useEffect(() => {
Linking.addEventListener('url', handleLinkEvent);
return () => {
Linking.removeEventListener('url', handleLinkEvent);
};
}, []);
For these cases you should use Linking.addEventListener
To complete #timboektoe's answer, react-navigation offers a subscribe function to listen to any URL received.
const subscribe = (listener) => {
const onReceiveURL = ({ url }) => { listener(url); };
const subscription = Linking.addEventListener('url', onReceiveURL);
return () => {
subscription.remove();
};
};
const linking = {
prefixes,
config,
getInitialURL,
subscribe,
};

pouchdb live is a little too fast for realtime chat

I am using the current vuex mutation to sync to my pouch/ couchdb which is excellent. However
As I am typing into text box I can type too fast and this can mean letters are not sent to sync, which is annoying but not a killer however if I edit in the middle and type at speed sometimes cursor will jump to the end, I want live as its live text but I would like to poll a little slower does anyone have any suggests.... there was a suggestion of using since : 'now' but that doesnt seem to slow it down
syncDB: () => {
pouchdb.replicate.from(remote).on('complete', function () {
store.commit('GET_ALL_NODES')
store.commit('GET_MY_NODES')
store.commit('GET_POSITIONS')
store.commit('GET_CONNECTIONS')
store.commit('GET_EMOJI')
// turn on two-way, continuous, retriable sync
pouchdb
.sync(remote, {
live: true,
retry: true,
attachments: true,
})
.on('change', function () {
// pop info into function to find out more
store.commit('GET_ALL_NODES')
store.commit('GET_MY_NODES')
store.commit('GET_POSITIONS')
store.commit('GET_CONNECTIONS')
store.commit('GET_EMOJI')
})
.on('paused', function () {
// replication paused (e.g. replication up to date, user went offline)
// console.log('replication paused')
})
.on('active', function () {
// replicate resumed (e.g. new changes replicating, user went back online)
//console.log('back active')
})
.on('denied', function () {
// a document failed to replicate (e.g. due to permissions)
})
.on('complete', function () {
// handle complete
})
.on('error', function (err) {
console.log(err)
})
})
},
I added a debounce via lodash to the text input which helps a lot it’s not perfect especially if you are editing in the middle of text but less jumps to the end and general start speedier typing isn’t an issue

Retrying Geolocation after error in React Native

I am using React Native's Geolocation API to get user's location or ask user to turn location on:
// Handle PermissionsAndroid
this.watchID = navigator.geolocation.watchPosition(
(position) => {
// Update position
},
(error) => {
switch (error.code)
{
Case 1: {
// Ask user to turn on Location (Permission has already been asked for)
}
}
}
);
Now, I want to retry the watchPosition if user ever turned location on at some later point.
Using AppState, I tried getting an event if user started to interact with the notification bar (maybe user is trying to turn on Location). But it only calls back if application is sent to background or is activated again (but not during notification bar interactions).
Since Geolocation conforms with W3 standards, I tried searching for solutions in web development world. But the only solution that I found, was using iFrame which is browser-only.
Also, a non-elegant solution would be to setInterval (say every 5 seconds) and then clearInterval only if a position has been returned.
Is there a proper way to do this?
You should initiate the flow by getting the current location first, then create the watch. The following is from the Geolocation docs.
navigator.geolocation.getCurrentPosition(
(position) => {
if (position) {
//Handle first position
}
},
(error) => (console.log(error)),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
this.watchID = navigator.geolocation.watchPosition((position) => {
if (position) {
// Handle new position
}
});
I've found this recovers from location errors itself, as well as handling permission requests (tested on iOS 10).

Multiple realms in React Native don't query realm object server correctly on first launch of app after install

I am having an issue dealing with multiple realms in React Native. I'm working on an app that allows users to use the app without having a subscription (using a local realm) and then at any point in their app journey they have the option of upgrading to a subscription with syncing (which uses sync to a realm object server).
When I start the app I check to see if they are using sync and if so I initialize a synced realm with their user and everything works great. I get all the data I expect.
However, when the app starts on first launch after install (that part about first launch after install is crucial) and I see that they don't use sync I initialize a local realm which I save data to until they decide to log in to their sync account (if they have one). At this point I attempt to pull information from the synced realm but it does not have the information that I saw when I only initialized the synced realm (in the case that on app startup I detect they use sync).
I am able to log in as the sync user but the data isn't there if I've previously initialized a local realm AND this logic gets run on the first launch of the app after install. The data only shows up from the realm object server when I initialize a local and synced realm on a secondary launch of the app (no reinstall before launching).
Here's a simple test script with dummy data in it with which I've been able to replicate the observed behavior:
const username = 'testuser2';
const password = 'supersecret';
const tld = 'REALM_OBJECT_SERVER_TLD';
class Test extends Realm.Object {}
Test.schema = {
name: 'Test',
properties: {
id: {
type: 'string',
},
}
};
function initLocalRealm() {
return new Realm({
path: 'local.realm',
schema: [Test],
});
}
function initSyncedRealmWithUser(user) {
return new Realm({
path: 'synced.realm',
sync: {
user,
url: `realm://${tld}:9080/~/data`,
},
schema: [Test],
});
}
function writeTestObjectWithId(realm, id) {
realm.write(() => {
realm.create('Test', {
id,
});
alert(`Test object with id: ${id}`);
});
}
initLocalRealm();
// setup
// uncomment this and comment out the login section to setup user on first run
// Realm.Sync.User.register(`http://${tld}:9080`, username, password, (error, user) => {
// if (error) {
// return;
// }
// const syncedRealm = initSyncedRealmWithUser(user);
// writeTestObjectWithId(syncedRealm, '1');
// });
// login
Realm.Sync.User.login(`http://${tld}:9080`, username, password, (error, user) => {
if (error) {
return;
}
const syncedRealm = initSyncedRealmWithUser(user);
alert(`Synced realm test objects: ${syncedRealm.objects('Test').length}`);
});
If you create a react native app and then add this code to the main components componentDidMount function you should see that on the first run of the app (after you've uncommented the register code once) you will see the Test collection length at 0, but then when you refresh you will see the Test collection length at 1.
Any help on this would be awesome.
Thanks!
running your code snippet, I get a length of 1 immediately as soon as I uncomment the login section. Could you try observing your synchronized realm with the Realm Browser and see if it seems to have the data you are expecting after registering the user?