Duplicate 'ScreenView' in Firebase DebugView - reactjs

Basically, my 'ScreenView' tracks are being duplicated when I use IOS.
Looking for the same problem, I saw that Firabase advised not to use 'setCurrentScreen', but here we use 'logEvent' for the track.
static screenView = async (info: FirebaseActualScreen) => {
try {
await FirebaseAnalytics.logEvent(LogTypes.SCREEN_VIEW, {
page_name: info?.name ?? '',
});
} catch (e) {
crashlytics().recordError(new Error(`Error to get actual screen - ${e}`));
}
};
Firebase DebugView
I have tried using the 'setCurrentScreen', even though it is not advisable, but the problem persists.

Related

UseEffect/useCallback is not triggering on very fast changes

I'm a Backend Dev and having limited knowledge in React still have to fix the problem
My project uses WebRTC for video calls. For signaling I'm using SignalR on my .NET backend.
On the frontend I have 2 classes:
signalRContext.tsx which holds an instance of HubConnection and listeners, onmessage is the relevant one.
const [currentSignal, setCurrentSignal] = useState<TCurrentSignal>
(InitialSignalR.currentSignal);
const initializeSignalListeners = (connection: HubConnection): void => {
console.log('START SIGNAL_R', connection);
connection.on('master', function (RoundInfo: IRoundInfo) {
console.log('MASTER', RoundInfo);
setCurrentSignal({ type: 'master', payload: RoundInfo });
});
connection.on('slave', function (RoundInfo: IRoundInfo) {
console.log('SLAVE', RoundInfo);
setCurrentSignal({ type: 'slave', payload: RoundInfo });
});
connection.on('message', function (message: TSignalRMessage) {
console.log('MESSAGE', message);
setCurrentSignal({ type: 'message', payload: message });
});
connection.on('endround', (payload) => {
console.log('END_ROUND');
setCurrentSignal({ type: 'endround', payload });
});
useRTCPeerConnection.ts which has the whole WebRtc relevant logic
import { useSignalRContext } from '../../../../core/contexts';
const {
signalrRRef,
currentSignal: { type, payload },
} = useSignalRContext();
useCallback(() => { //tried UseEffect as well
if (type === 'message') {
console.log('PAYLOAD', payload);
onMessage(payload as TSignalRMessage);
return;
}
}, [type, payload]);
My problem starts when WebRTC starts exchanging the ICE candidates and sends them sometimes twice per millisecond (see the last column).
The connection.on('message'... listener seems to be fast enough, I'm seeing all console.log('MESSAGE'... outputs in the console.
My problem is that the useCallback/useEffect logic is not firing on every payload change, like for 20 MESSAGE outputs I'm seeing 4-7 PAYLOAD outputs.
My assumption is that useEffect is simply not designed for such quick changes.
Is there any other concept better suitable to solve this problem or any improvement I could do here? Thinking on .NET I would just use the composition pattern and call the relevant method from peer connection class within the event handler in signalR class but not sure how to fix it here.
P.S. I've tried to wait until ICE candidates are gathered and sending them at once but the performance becomes not acceptable.

Vue Fetch Behaving differently on Local vs. Deployed

I feel that I am implementing Vuex Store or async-await incorrectly.
My goal is to pull a set of badges (we call them patches) from my content management service. I need the list to be up to date whenever a new badge is added in the future (which will be infrequent but not never). I don't know how to make a check that will refresh the list whenever the current badge count is different from the number of badges in the cms but that is beside the current problem.
I have an array, rawPatches, in Vuex that should only be built if rawPatches.length <= 0. Once built it should have 60 items pulled from my content management service. This seems to work fine when I do npm run dev on my local machine. However, once pushed to the development site and compiled through Netlify, the array is messed up. When I visit another page and come back to where the length check is the array has an extra 60 items. So when I leave and come back twice then the array has 180 items, and so on and so forth. Also, when I close the window and then come back the incorrect count remains. I guess this means that the Vuex State is cached? I don't know if the length check doesn't get executed or if the array doesn't exist when the check happens but then does exist when new items are added because I'm awaiting the build function. I really have no idea what is going on but I have been trying to sort it out for a few months and am ripping my hair out.
I am using async-await because readPersonalPatches relies on the patches being in Vuex Store.
index.js
export const state = () => ({
rawPatches: [],
});
export const mutations = {
addToArray: (state, payload) => {
state[payload.arr].push(payload.value);
},
}
export const actions = {
async readPatches({ commit, state }) {
console.log('inside of readPatches', state.rawPatches.length);
const patches = await this.$content('patches').fetch();
patches.forEach((patch) => {
commit('addToArray', { arr: 'rawPatches', value: patch });
if (patch.categories) {
if (
JSON.stringify(patch.categories).includes('orbit') ||
JSON.stringify(patch.categories).includes('point')
) {
commit('addToArray', { arr: 'geographicPatches', value: patch });
}
}
if (patch.isSecret) {
commit('addToArray', { arr: 'secretPatches', value: patch });
}
});
console.log('After adding patches', state.rawPatches);
},
}
header component
async fetch() {
console.log('Does this work?');
try {
console.log('length', this.rawPatches.length <= 0);
if (this.rawPatches.length <= 0) {
await this.readPatches({ context: this.$nuxt.context });
}
this.readPersonalPatches();
} catch (error) {
console.log(error);
}
},
Locally, the console reads:
Does this work?
length true
inside of readPatches 0
after reading patches [...]
However, the console is blank on the dev server.
Thank you for any help with this!!

React native async storage issues

In my react native app I am trying to save data into my local storage. It works fine most of the time but sometime I get error while setting the item.
So here is the code for me setting the item
async setString(key: string, value: any) {
try {
return await AsyncStorage.setItem(key, value)
} catch (e) {
LogService.logError(
'apiClient',
'apptype',
`Error setting local storage, key: ${key} error: ${JSON.stringify(e)}`,
)
}
}
One of the thing is that my error doesn't prints.
IOS users are having this issues
Do I need to first delete the item and then write to it? Doesn't setString override the value?
Is there any storage problem on the client?
Try using JSON.parse() when getting and JSON.stringify() when setting it
It's worked for me, you can try this.
useEffect(() => {
AsyncStorage.getItem('isLaunched').then((value) => {
AsyncStorage.setItem('isLaunched', 'true'); // No need to wait for `setItem` to finish, although you might want to handle errors
}); // Add some error handling, also you can simply do
}, []);

Async Clipboard API "ClipboardItem is not defined" - Reactjs copy image to Clipboard

I'm working on React js, I created my app with create-react-app using npm. I was trying to build a button that takes an image and writes it to the clipboard. Fourtunately I found this npm library that seems to work fine! But keeps me thinking why I couldn't use the ¿built-in? Asynchronous Clipboard API to copy the image (the text copy works fine). I read a really enlightening guide here, and kept reading other great guide here, so I tried all the codes suggested, there and in other pages (despite they don't seem to really change the functionality, I got to try). I came with the same error in every try that impedes to compile: "'ClipboardItem' is not defined no-undef". One code for example was this one:
const response = await fetch('valid img url of a png image');
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob})]);
It seems to be simple, easy to follow. The problem is when you need to put the data in a form the Clipboard can read it, make it a blob, because I need the ClipboardItem constructor, and my app seems to be unable to recognize it as such. Keeps returning ClipboardItem is not defined or, if I somehow define it, says it's not a constructor, of course. I tried with other constructors like Blob(), but had the same problem. The last thing kept me thinking that, since I'm new in the programming world, if there is something kinda basic I don't know of the interaction of Web Apis like this one with node or Reactjs, and if there is a solution, of course! Thanks in advance, you guys are great!
Edit: adding the whole component code as requested:
import React from "react";
function TestingClipAPI () {
async function handleScreenshot () {
const response = await fetch('https://i.postimg.cc/d0hR8HfP/telefono.png');
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob})]);
};
return (
<div>
<button onClick={handleScreenshot} id="buttonID">test</button>
</div>
)
};
export default TestingClipAPI;
Possible issue: This might be because of CRA (Create-React-App) config - similar issue. Something like the library linked can be done, create a canvas and copy the image from there.
Solution or a way to make it work anyway: make a call this way before using ClipboardItem:
const { ClipboardItem } = window;
Note: this also works with other constructors like toBlob and HTMLCanvasElement that had the same issue.
Things to look for:
Browser support Clipboard
Secure origin on HTTPS or localhost. See this post.
How the function is being called - in the OP's case - onClick & asynchronous.
The issue is that onClick are not asynchronous by default and you are not awaiting the response and you also have a typo in navigator.clipboard.
const handleScreenshot = async () => {
try {
const response = await fetch(
"https://i.postimg.cc/d0hR8HfP/telefono.png"
);
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({ "image/png": blob }),
]);
} catch (err) {
console.error(err);
}
}
return (
<button onClick={async () => await handleScreenshot()} id="buttonID">
test
</button>
);
There are tradeoff between inline function and below are alternatives. I'd personally use the latter method.
function handleScreenshot() {
async function screenShot() {
try {
const response = await fetch(
"https://i.postimg.cc/d0hR8HfP/telefono.png"
);
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({ "image/png": blob }),
]);
} catch (err) {
console.error(err);
}
}
screenShot();
}
return (
<button onClick={handleScreenshot} id="buttonID">
test
</button>
);
Lastly, you can return a chained promise.
Simply add window in front of ClipboardItem like the following
window.ClipboardItem(...)
Unfortunately, as of the time of this answer, ClipboardItem isn't supported in Firefox. (Support can be enabled via an about:config setting; but of course, most Internet users will not have done this.)
Source: https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem#browser_compatibility

Can't get the Generic Sensor API to work in a React app

I'm trying to implement the Generic Sensor API in a React app.
https://www.w3.org/TR/generic-sensor/#the-sensor-interface
I keep getting an error when I try to implement any of the sensors in my code.
For example:
var sensor1 = new AmbientLightSensor();
I get the error: Cannot find name: 'AmbientLightSensor'.
I assume that I need an import statement in my code. All of the examples I've found only include LitElement. I've even tried that but still get the unknown error.
What import statements do I need in my typescript code?
What npm packages do I need?
Below is the typescript code I'm using.
I'm getting a typescript error:
/Users/scoleman/dev/current/bigbrother/src/utility/testAccel.ts(14,24):
Cannot find name 'AmbientLightSensor'. TS2304
export const testAccel = async (
databaseName: string,
) => {
const {state} = await navigator.permissions.query({
name: "ambient-light-sensor"
});
if (state !== "granted") {
console.warn("You haven't granted permission to use the light sensor");
return;
}
const sensor = new AmbientLightSensor();
sensor.addEventListener("reading", () => {
console.log(sensor.illuminance);
});
sensor.addEventListener("error", (err: any) => {
console.error(err);
});
sensor.start();
};
I was able to get these api's running using the polyfill at:
https://github.com/kenchris/sensor-polyfills
This would depend entirely on the browser you are using. I don't think FireFox supports it at the moment so I will focus on Chrome.
Firstly, you might need to be serving your site over HTTPS. It seems like this almost varies from permission to permission and also some are available on a localhost URL no matter what.
Secondly, for Chrome, you have to enable the "Generic Sensor Extra Classes" flag in Chrome at the chrome://flags/#enable-generic-sensor-extra-classes page.
Next, you need to make sure that have permission from the user to use the sensor, then you could actually use it. A snippet that would check that is as follows:
(async function(){
const {state} = await navigator.permissions.query({
name: "ambient-light-sensor"
});
if (state !== "granted") {
console.warn("You haven't granted permission to use the light sensor");
return;
}
const sensor = new AmbientLightSensor();
sensor.addEventListener("reading", () => {
console.log(sensor.illuminance);
});
sensor.addEventListener("error", err => {
console.error(err);
});
sensor.start();
}());

Resources