Sync offline data in react progressive web app from indexeddb - javascript

Hi I am creating a progressive web app with react and redux I have converted it to the progressive web app and now I am also storing the data into indexeddb to but I am having trouble syncing offline data.
I have implemented this approach in my App component I listening for online and offline events of the browser then I am syncing the offline data.
Here is my code.
componentWillUnmount() {
window.removeEventListener('offline',() => {
this.syncOfflineData()
});
window.removeEventListener('online',() => {
this.syncOfflineData()
});
}
syncOfflineData = () => {
console.log('a ajax request to sync offline data')
}
The syncOfflineData function is working but i am having trouble with it for example if i have same page open in multiple tabs for examples 4 tabs then it will run syncOfflineData function 4 times due to 4 open tabs so it is adding the same record 4 times in database due to sending ajax request 4 times 1 for each tab.
I have also tried adding a unique value from client side but the syncOfflineData function runs at the same time when it connects to internet so it means 4 ajax requests are sent to the server at the same time due to that my client unique values are not found in database so it inserts 4 same records in database.
Can anyone let me know Is their a way for me to sync correctly like no matter how many tabs are open it sends only requests not each same request for each new tab when it connects or disconnects to interent.
kindly help me with this.

Related

React - setInterval() behaving differently on mobile browser

I am perplexed on an issue I am facing. I have developed a MERN app, where one component within the app is displaying data as a chart from my redux store. In order to give some semblance of "dynamic" data, I have set up a setInterval inside a useEffect hook to fetch the data and update the store every 60 seconds.
Now when I deploy the application on a on-prem server and view the app through a browser on my desktop, the functionality works as expected. Every minute a GET request is made to my backend and new data is being displayed. When this happens ONLY the graph component re-renders - i.e the WHOLE webpage does't reload.
// Get all alerts upon render and at regular intervals of 1 minute.
useEffect(() => {
let fetchInterval = setInterval(() => {
dispatch(getAlert()) //This is the GET request
.then(() => {
dispatch(reset())
})
}, 60000)
return () => clearInterval(fetchInterval)
},[])
But when I access the exact same app through a mobile browser, every minute the ENTIRE web page refreshes - identical to if I had pressed the refresh button. This would be greatly annoying to the user as any selections they would have made would be wiped out.
Can anyone tell me how I can have the same functionality on the mobile browser as compared to the desktop? Also why does this happen? Is this an optimisation by mobile web browsers?
Another thing I noticed is that the data is very slow to fetch on my mobile device even if I am using the same wifi internet connection. Can this be improved?
Greatly appreciate your support!

Run a persistent web worker in the background without getting throttled

I would like to run a web worker in the background (on mobile, it works on desktop) which does an action every minute by sending an HTTP request. Unfortunately, after having the website in the background for about 5 minutes, no HTTP request will be sent anymore... All network requests will resume once you go back to the website.
It seems like the web worker is not allowed to be run in the background, at least not on mobile, as it works fine on desktop. I could not find any source stating why it is throttled, and what can be done about it. I found a similar issue dating from 2017, which is 4 years ago and has not been answered quite the way I want it and might also be outdated.
I thought of the following solutions:
Normally in native Android you can show a notification which will ensure that your app keeps running in the background, I was wondering if this would also work on web in combination with web workers.
If you open a web socket in your web worker, will it keep your web worker alive in the background?
Progressive web app. Does not seem to keep it active unfortunately..
Is there anything I could do about this?
All modern browsers restrict background usage. It has a really simple reason: Background tasks require resources, and users dont want a million websites in the background to eat all your RAM. And malicious websites could just use the CPU from users for bitcoin mining etc.
But there is a way to do stuff in the background. You already mentioned it in the question: You need to send push notifications. You can just include a fetch() in your push notification handler.
But here's the catch: You have to send a notification every time you want your site to fetch something, or your requests will always/sometimes be blocked depending on your browser. From MDN:
Activating a service worker to deliver a push message can result in increased resource usage, particularly of the battery. Different browsers have different schemes for handling this, there is currently no standard mechanism. Firefox allows a limited number (quota) of push messages to be sent to an application, although Push messages that generate notifications are exempt from this limit. The limit is refreshed each time the site is visited. In comparison, Chrome applies no limit, but requires that every push message causes a notification to be displayed.
You just need to set up Push Notifications. There's a great guide from Google that you can follow if you don't know how to set up push notifications.
An implementation in a service worker would look like this:
self.addEventListener('push', function(event) {
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}
// The HTTP request
fetch("...");
var data = {};
if (event.data) {
data = event.data.json();
}
var title = data.title || "Background activity";
var message = data.message || "You can ignore this";
var icon = "images/new-notification.png";
var notification = new Notification(title, {
body: message,
tag: 'simple-push-demo-notification',
icon: icon
});
notification.addEventListener('click', function() {
if (clients.openWindow) {
clients.openWindow('https://example.blog.com/2015/03/04/something-new.html');
}
});
});
(Code copied from MDN)

Get real time updates from Microsoft Graph API (beta) Communication API

I am current using Microsoft Graph API (beta) to get Presence Status e.g. Online, away etc. in an spfx webpart (using React) using GraphClient:
this.props.context.msGraphClientFactory.getClient().then(async (client: MSGraphClient) => {
let response = await client
.api('/communications/getPresencesByUserId')
.version('beta')
.post(postData)
console.log("Communication API Response: "+ response);
this.usersWithPresence = response.value;
});
This is working fine, but to get updated status of a user, I have to refresh the page so another API call is made and updated presence status. I want to do it like this happens in 'Skype'.
What I need is suggestions about a mechanism that I can apply to get
real time updates in user's presence status, so as soon as user
updates the status this is reflected in my webpart. I know I can use
setInterval or setTimeout functions to request for presence status
after specific intervals but for learning purposes i don't want to
request API this way again and again but rather getting updated
message from server like this happens using web sockets. How a web
socket sort of stuff can be applied with this API?
your suggestions are welcome.
Today this API doesn't support any kind of subscription mechanism to when the status changes. There is a uservoice entry you can upvote for it. That means the only way to get any changes is to periodically poll it. As for socket io, the only support today is for SharePoint lists, for any other resource you need to stand up your own infrastructure to relay the message.

How to notify without websocket

I want to integrate a simple notification system in my react application. I want to notify for example:
- new post (when the user post the system need time to transcode the media attached and the publication)
- missing settings (the user need to compile some information)
- interesting posts etc..
There is a simple way to add a websocket, like socket.io, to a reactjs app with an aws lambda backend?
All the notification not need to be read in real time, maybe an ajax call every 2 minutes can solve my problem, but, in this case, someone can help me avoid ajax call if the app isn't used(like if the app remain opened in a foreground tab...)
componentDidMount() {
this.liveUpdate()
setInterval(this.liveUpdate, 120000);
}
liveUpdate() {
axios.get(endpoint.posts+'/live/', cfg)
.then(res => {
// ...
});
}
This code is in the footer component, the call happen every 120 seconds, but the call will still happen also if a user leave the application opened in the browser and not use it, this on a lambda backend mean a waste of money.
There are 3 main ways of notifying that I can think of at the moment...
Long polling (using ajax etc)
Websocket
Push Notification
Push (though) requires permission from the user

Creating a redux middleware that uses websocket api for syncing server data state with client

I have a server API, that is based on websockets. If the client connects, he must first send a message, and if a success message from server is emitted, client can start working with the server data.
Now i have a angular4 based app, that if the user opens several view components, each component registers to specific events from the API (Using a Websockets service). If the a new state comes from server, the views can update itself. Views can also send update events to server, that recalculates data and sends updates via websockets. The server itself holds a state of the data.
But now, no real client state exists. Without overcomplicating this post (i exclude routing etc), the main target for me now is to integrate redux for managing the state in UI, so that the user can reload the page and see last opened views with a synced with server data.
The current approach of me, is to create create a
Backend service, that holds an WebSocketSubject (RxJS) and manages the sending or recieving from server. I pass an connection observable, that dispatches an event if connection exist. I also have a Subscription inside the service, that dispatches all the websockets push messages as redux events and acts like a middleware
/** this code is a binding to redux word, and acts as middleware push
* #type {Subscription}
*/
this.subscription = this.socket$.subscribe(
(msg) => this.ngRedux.dispatch({type: msg.method, value: msg.parameters}),
(err) => this.ngRedux.dispatch({type: AppActions.CONNECTION_FAILED}),
() => this.ngRedux.dispatch({type: AppActions.CONNECTION_CLOSED})
);
The idea is that i will have reducers, that will react on data state changes from server e.g. if an error is send and a specific view listens to it, it should have a error state.
case BackendStreams.some__error:
return Object.assign({}, lastState, {
error: 'Could not do some calcucations'
});
The server code itself is deterministic and works works the messages from one stack, so i can expect that if i send same 4 messages in same sequence, i will receive same responses.
The problem what i have now, is that if i reload the window (or use the DevTools), the state is recreated, but none of the events are resent to backend. How can i accomplish this? Should i somehow (what tools) tell Redux that some of impurity exists, or have something like a state machine? Im just guessing...

Categories

Resources