Best Practice: handlng no network in a ReactNative / Redux App - react-native

I've built a ReactNative app that uses redux, as well as Wix's react-native-navigation library (HIGHLY recommend btw), and am trying to improve the user experience when network connection is lost - really just a simple alert that lets the user know.
I've got all of my fetch() calls in one api.js lib file, and what I would love to do, is wrap each request with a function that checks for connection before fetching (as opposed to doing some sort of per-component implementation I've seen in other SO suggestions).
I've read a bunch about facebook's NetInfo (https://facebook.github.io/react-native/docs/netinfo.html) API, however there are still open issues on it w/ regards to the simple NetInfo.isConnected.fetch().then((isConnected) => {} use case (it always returns false, per the issues open).
I've tried something like this inside the fetch function:
static get(route, params, header) {
return NetInfo.isConnected.fetch().then((isConnected) => {
if ( isConnected )
{
// Run / return your API call
}
else
{
Alert.alert('No Internet Connection', 'Please connect and retry.',[{text: 'OK'}],{ cancelable: false });
}
});
}
I'm wondering if anyone has either successfully utilized the NetInfo api in this way, or if you've come across a better solution for this (likely) common problem.

Related

VueJS and ElectronJS | VueJS stops rendering completely when I import ipcRenderer in a component

So I am coding a VueJS and ElectronJS template which can be found here: https://github.com/dev-aethex/electronjstemplate
My code works something like this,
Inside of my Vue component I access a global pre constructed class called MainProcessInterface and when it's constructed it first checks if vue is compiled for running in a development server. If it's in a dev server it will connect to the dev socket which electrons main process will host if electron is in dev mode and not compiled. This method seems to be working great, I had to use a socket because vue dev server is being loaded into electron via loadURL and so vue has no clue what ipcRenderer is. Inside the main process interface, if vue is compiled it will instead use the ipcRenderer.send() method. This is were the problem was born.
As soon as Vue runs thought the TS code, it sees ipcRenderer.send and freaks out while printing an error to the electron window console saying fs.existsSync does not exist or is defined.
I can't find a way around this. I though maybe i'll split MainProcessInterface into 2 peices, one for ipc and the other for websockets. Although it isn't a very good way, so before implementing it, I would like to know if there is a better more proper way of doing such.
I had a similar issue with React. Are you importing the ipcRenderer object somewhere in your build process? You might want to make sure it references the correct variable. I tried to drop this in as a comment but it wouldn't fit:
//index.html (index.ejs) for me... This is in the main HTML entry point
var IPC = null;
try {
IPC = require('electron').ipcRenderer;
console.log('IPC IS: ' + IPC)
} catch (err) {
console.log('CRICITCAL ERROR: IPC NOT ENABLED')
console.log(err)
IPC = null;
}
Then I initialize off that context in React with a startup here:
setTimeout(()=>{
console.log('----------------HACK FIRED POST REHYDRATE')
window.REDUX_STORE.dispatch(
(dispatch, getState) => {
const _state = getState()
if(window.IPC) {
if(_state.osc && _state.osc.on) {
dispatch( reconnectToEos() )
} else {
dispatch( updateStatus('[OSC Startup: DISCONNECTED]', ))
}
console.log('\t------------ELECTRON')
} else {
//Shut off OSC
dispatch( updateOscKey('on', false) )
dispatch( updateStatus('[WebApp, OSC disabled]', ))
console.log('\t------------WEB')
}
}
)
}, 1000)
Basically I'm using a global variable (window.IPC) to initialize my app so I don't import a bad variable in my build process. I have a fair number of Electron APIs where this alleviates the issues with building via Webpack.
I hope this helps!

React native custom internet phone call

I have a 3 part question from important to less important:
Does someone know if there is a package to do phone calls trough the internet as Whatsapp and Facebook do?
Would it even be possible to do it without a phone number?
For example, only knowing someone's device id.
And can you even make your "ring page" custom? So adding functionalities while calling.
Thank you in advance!
Yes this is possible. There are plenty of ways to attack this but I would recommend using a React Native wrapper for Twilio (https://github.com/hoxfon/react-native-twilio-programmable-voice).
import TwilioVoice from 'react-native-twilio-programmable-voice'
// ...
// initialize the Programmable Voice SDK passing an access token obtained from the server.
// Listen to deviceReady and deviceNotReady events to see whether the initialization succeeded.
async function initTelephony() {
try {
const accessToken = await getAccessTokenFromServer()
const success = await TwilioVoice.initWithToken(accessToken)
} catch (err) {
console.err(err)
}
}
// iOS Only
function initTelephonyWithUrl(url) {
TwilioVoice.initWithTokenUrl(url)
try {
TwilioVoice.configureCallKit({
appName: 'TwilioVoiceExample', // Required param
imageName: 'my_image_name_in_bundle', // OPTIONAL
ringtoneSound: 'my_ringtone_sound_filename_in_bundle' // OPTIONAL
})
} catch (err) {
console.err(err)
}
For that approach I believe you have to have a phone number but you can build out the ui however you like.
If you are not into the Twilio approach, you can use pure JS libraries to do the trick such as SipJS.
There are also tutorials on Youtube which can lead you through the process like this.
I recommend you Voximplant, https://voximplant.com/docs/references/articles/quickstart,
it's easy to use and has clear documentation.

How to implement Auth0 server-side with Nuxtjs?

I have a Nuxt app with authentication already running in universal mode.
I'm trying to convert the authentication service to Auth0. I'm following the Vue quickstart, but I discovered that auth0-js is a client side library since it uses a lot of 'window'-stuff that is not available on the server-side of Nuxt.
However, I got it kind of working by making it a client-side plugin and wrap all functions (that is calling the authservice in the lifecycle hooks) in a process.client check. It works "kind of" because when going to the protected page whilst not logged in, it flashes the page before being redirected to login page (since its rendered on the server-side as well, but the check only happens once it's delivered on the client side I presume).
My question now is: What can I do in order to add the check to server-side as well? (or at least make sure that the protected pages isn't flashed before being redirected).
What I've tried so far:
Saving the payload and the logged-in state in the store and check in some custom middleware, but that didn't do the trick.
Also, it seems to me that #nuxt/auth is outdated or something and the nuxt auth0 example as well. It uses auth0-lock while I'm using the new auth0 universal.
Anyone have suggestions on how to solve this issue? Thanks in advance!
not sure if this will be any help and have only answered a few questions (other account long time ago).
Update.. I read my answer then the question title (I think my answer does cover some of your context), but in regards to the title you could also look at using auth as a plugin. You can then handle stuff there before the page is hit.
I am not sure how your code is implemented, but this may help (hopefully).
If you are not using Vuex, I strong recommend it. Nuxt Vuex Store Guide
// index/store.js
// At least have the store initialized, but its most likely going to be used..
// page.vue
<template>
...
<div v-else-if="!$auth.loggedIn">
{{ test }}
</div>
...
...
data() {
if (!this.$auth.loggedIn) {
const test = 'Only this will load, no flash'
return { test }
}
}
$auth.loggedIn is built in, I read it ..somewhere.. in the docs
This will solve the no flash issue, you can also take advantage of a loader screen and asyncData to check the state before rendering the view to avoid a flash and populate data if it hangs.
You could also try using Vuex Actions, I am currently playing with these 2 in the process of where I am now. Learning about nuxtServerInit()
// store/index.js
import axios from 'axios'
export const actions = {
nuxtServerInit ({commit}, {request}) {
// This is good if you have the user in your request or other server side stuff
if (request.user) commit('SET_USER', request.user)
},
async GET_USER({ commit }, username) {
const user = await axios.get(`/user/${username}`)
if (user) commit('SET_USER', user)
}
}
export const mutations = {
SET_USER(state, user) {
// simple set for now
state.auth.user = user || null
}
}
The second one is combined using the fetch() method on the page itself.
// page.vue
async fetch({ $auth, store }) {
await store.dispatch('GET_USER', $auth.$state.user)
}
Now you can call $auth.user in your code as needed.
$auth.user is another built in I read ..somewhere..
You can also call $auth.user with the $auth.loggedIn to check if user exists on top of being logged in $auth.user && $auth.loggedIn.
It may be this.$auth.<value> depending on where you are trying to reference it.
I learned the asyncData() gets call first and logs in my server, then data() logs values in the server console as well (false, null), but in my Brave console they're undefined, i'd like an answer to that lol
I have been struggling with trying to get Auth0 to work how I wanted with JWTs, but as I kept crawling I found useful bits along the way (even in old demos such as the one you mentioned, just nothing with the lock stuff...). Also in terms of express and my API in general... Anyways, hope this helped (someone).

Nuxt Vuex Store Cookies Issue

Good time of the day!
After a few weeks of development of my project, i've decided to migrate from plain Vue to Nuxt.
Mainly because i need SSR, although i know that Google can execute JS presented on the page and therefore generate appropriate content for their search bot.
Another reason is a general workflow of the project development. I like idea with automatic instantiation of routes, store, etc.
I've faced, however, a pretty strange behavior of the application when it is running in the mode: universal instead of mode: spa. And i don't want to switch to mode: spa since then i lose the SSR i was migrating for in the first place.
I' have an account module in the store - account.js which is responsible for handling any operations related to the account management, such as login/logout, get profile of authenticated user, store the token obtained from the login request as well as the logic for handling the 2FA TOTP procedure.
In my legacy application, i was able to get the token from the cookies by just using the following bit of the code
import Cookies from 'js-cookie';
export const state = {
user: null,
token: Cookies.get('token')
}
And save token after the successful authentication by executing the following mutation:
[types.ACCOUNT_SAVE_TOKEN] (state, { token, remember }) {
state.token = token;
Cookies.set('token', token, {
expires: 365,
httpOnly: true
});
}
But after migration to Nuxt.js, every time im loggin in, the token value in the state is getting populated, but no cookie is set, and after navigating to the other page inside the project (it is pwa, so no reloading, etc) token is reset back to null.
This issue however is gone if application is switched to the mode: spa from mode: universal and everything is working just fine.
I've read many issues on the github as well as done pretty big portion of crawling throught the websites which are trying to solve the same issue, though none of the suggestions are working for me.
I've even installed the cookie-universal-nuxt package from NPM which claims to be working with the SSR, but yet every time I'm trying to access this.$cookies.get('token') in the state, or anywhere else (mutations for example), I'm just getting error about using the method (get/set/remove) on null.
Does anyone know or have an idea on how to overcome this issue, at least if it is possible without going back to the mode: spa?
P.S. Running npm run build|generate yields same files as for the normal vue (without the content, just the structure until the target element is readched) while in mode: spa.
Okay, after around 12 hours trying to wrap my head around this issue, i've decided to go the 'dirty' way and create middleware which is doing, in my opinion, way to much processing on each request.
import CookieParser from 'cookieparser';
export default async function ({ store, req }) {
if (!store.getters['account/check']) {
if (!store.state.account.token) {
if (process.server) {
let requestCookies = CookieParser.parse(req.headers.cookie);
if (requestCookies.hasOwnProperty('token')) {
store.dispatch('account/saveToken', {
token: requestCookies.token,
remember: true
});
}
}
}
if (store.state.account.token) {
if (!store.state.account.user) {
try {
await store.dispatch('account/fetchUser');
} catch (error) { }
}
}
}
return Promise.resolve();
}
Seems like useCookie has been created for this use case

AsyncStorage is not returning the callback

I am using redux-persist in a react native project, that runs just fine in a broad number of devices except Android 7. I am trying to debug the problem on why my local storage is nor persisting and found this:
The following code executes inside React Native component lifecycle's
componentDidMount() {
attachObservables(store)
setInterval(async () => {
console.log('Inside setInterval')
const data = await AsyncStorage.getAllKeys()
console.log('inside the getAllKeys')
data.forEach(async k => {
const value = await AsyncStorage.getItem(k)
console.group(k)
console.log(value)
console.groupEnd()
})
}, 3000)
}
Code after 'Inside setInterval' is never called. It only runs once if outside the setInterval. If I call once the code outside the setInterval it appears to run just fine. I also tried callback format vs async / await version but it does not seem to matter.
Same problem I had using firebase js library (callbacks never return after the first one). I am now looking for alternatives to workaround the problem.
Any ideas?
As of React Native 0.51 in some Android versions, the runtime can get blocked by other native modules, impeding the resolution of the mentioned methods.
It can be fixed via https://github.com/facebook/react-native/issues/14101#issuecomment-345563563, ensuring this methods use a free thread from the thread pool.
A PR has been submitted and I hope that will be released in future versions. If you want it to use this fix right now, it is available here https://github.com/netbeast/react-native
EDIT:
I am not experiencing this anymore on real devices over react-native#0.53, anyhow others have also reported, so the issue is still open.