Sentry for micro frontends - reactjs

Is there any possibility to initialise Sentry twice on a page? Use case would be error tracking for parts of the app that are inserted as microfrontend.
So errors happen in this part of the app should be send to the teams own sentry project. I also wonder if there is any way filter the errors so only the ones that are relevant for the microfrontend are send and others are filtered out. Could we use reacts error boundaries for that?

Looks like there is a way to initialize something called Hub with a second dsn like this:
import {BrowserClient, Hub} from '#sentry/browser';
const client = new BrowserClient({
dsn: 'micorFrontEndSntryInstance'
});
const hub = new Hub(client)
this hub can passed to an ErrorBoundary wrapping your component.
In every componentDidCatch we can then send the error to the micro frontends sentry:
componentDidCatch(error, errorInfo) {
this.props.hub.run(currentHub => {
currentHub.withScope((scope) => {
scope.setExtras(errorInfo);
currentHub.captureException(error);
});
})
}
All the code is from this example implementation.

Related

Specifically, how does Reactjs retrieve data from firebase function triggers?

I am using express to create my firebase functions, and I understand how to create regular callable functions. I am lost however on the exact way to implement trigger functions for the background (i.e. onCreate, onDelete, onUpdate, onWrite), as well as how Reactjs in the frontend is supposed to receive the data.
The scenario I have is a generic chat system that uses react, firebase functions with express and realtime database. I am generally confused on the process of using triggers for when someone sends a message, to update another user's frontend data.
I have had a hard time finding a tutorial or documentation on the combination of these questions. Any links or a basic programmatic examples of the life cycle would be wonderful.
The parts I do understand is the way to write a trigger function:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return change.after.ref.parent.child('uppercase').set(uppercase);
});
But I don't understand how this is being called or how the data from this reaches frontend code.
Background functions cannot return anything to client. They run after a certain event i.e. onWrite() in this case. If you want to update data at /messages/{pushId}/original to other users then you'll have to use Firebase Client SDK to listen to that path:
import { getDatabase, ref, onValue} from "firebase/database";
const db = getDatabase();
const msgRef = ref(db, `/messages/${pushId}/original`);
onValue(msgRef, (snapshot) => {
const data = snapshot.val();
console.log(data)
});
You can also listen to /messages/${pushId} with onChildAdded() to get notified about any new node under that path.

why does ether provider return nothing when refreshing page on a react website?

I have been creating a front end to interact with a smart contract. The smart contract that I has been one that I deployed on test network. The way I am setting up the provider uses the 'ether' library and the provider that I use is infura.
async function loadWeb3() {
// console.log('hit');
if (window.ethereum) {
window.ethereum.enable()
setProvider(`await new ethers.providers.InfuraProvider('rinkeby',API_KEY)`);
console.log(provider);
}
}
The above function is how I try to set the provider to a useState. The connection to the contract works when I am running it on a local host and change some aspect of the react app and save and thus updates the react app on the host. Although this does not work when I choose to refresh the page. Instead when I check the output of
await new ethers.providers.InfuraProvider('rinkeby',API_KEY)
The returned value is " ", I am able to see this by printing it on the console, but when I print it using the above steps of saving some change while in development the output is instead
"InfuraProvider {_isProvider: true, _events: Array(0), _emitted: {…}, disableCcipRead: false, formatter: Formatter, …}"
I am using a useEffect within the component to call the function "loadWeb3". I have not found a way to fix this or why this would be happening. Any help is appreciated :)

Handling OAuth with React 18 useEffect hook running twice

Background
I have recently upgraded a fairly sizeable React app to React 18 and for the most part it has been great. One of the key changes is the new double mount in development causing useEffect hooks to all run twice, this is clearly documented in their docs.
I have read their new effect documentation https://beta.reactjs.org/learn/lifecycle-of-reactive-effects and although it is quite detailed there is a use case I believe I have found which is not very well covered.
The issue
Essentially the issue I have run into is I am implementing OAuth integration with a third-party product. The flow:
-> User clicks create integration -> Redirect to product login -> Gets redirected back to our app with authorisation code -> We hit our API to finalise the integration (HTTP POST request)
The problem comes now that the useEffect hook runs twice it means that we would hit this last POST request twice, first one would succeed and the second would fail because the integration is already setup.
This is not potentially a major issue but the user would see an error message even though the request worked and just feels like a bad pattern.
Considered solutions
Refactoring to use a button
I could potentially get the user to click a button on the redirect URL after they have logged into the third-party product. This would work and seems to be what the React guides recommend (Although different use case they suggested - https://beta.reactjs.org/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers).
The problem with this is that the user has already clicked a button to create the integration so it feels like a worse user experience.
Ignore the duplicate API call
This issue is only a problem in development however it is still a bit annoying and feels like an issue I want to explore further
Code setup
I have simplified the code for this example but hopefully this gives a rough idea of how the intended code is meant to function.
const IntegrationRedirect: React.FC = () => {
const navigate = useNavigate();
const organisationIntegrationsService = useOrganisationIntegrationsService();
// Make call on the mount of this component
useEffect(() => {
// Call the method
handleCreateIntegration();
}, []);
const handleCreateIntegration = async (): Promise<void> => {
// Setup request
const request: ICreateIntegration = {
authorisationCode: ''
};
try {
// Make service call
const setupIntegrationResponse = await organisationIntegrationsService.createIntegration(request);
// Handle error
if (setupIntegrationResponse.data.errors) {
throw 'Failed to setup integrations';
}
// Navigate away on success
routes.organisation.integrations.navigate(navigate);
}
catch (error) {
// Handle error
}
};
return ();
};
What I am after
I am after suggestions based on the React 18 changes that would handle this situation, I feel that although this is a little specific/niche it is still a viable use case. It would be good to have a clean way to handle this as OAuth integration is quite a common flow for integration between products.
You can use the useRef() together with useEffect() for a workaround
const effectRan = useRef(false)
useEffect(() => {
if (effectRan.current === false) {
// do the async data fetch here
handleCreateIntegration();
}
//cleanup function
return () => {
effectRan.current = true // this will be set to true on the initial unmount
}
}, []);
This is a workaround suggested by Dave Gray on his youtube channel https://www.youtube.com/watch?v=81faZzp18NM

Is there a way to track a user active time spent in the React web application via Google Analytics?

Let's say an user with user_id(1000) and email(user101#example.com) logged into the reactjs based web application and browsed a few pages for 2mins and then moved to other application tabs/windows for 30mins and came back to the web application and browsed the app for 5more mins on April 1st 2021.
I would like track/get this user's time spent report in the Google Analytics report saying user101#example.com with user_id(1000) has spent 7mins on April 1st 2021. Is there a way to track the same via GA if possible with react-ga, if it is possible how can we do it?
As of now with react-ga I'm tracking the userid property like the below:
ReactGA.set({userId});
If it is not possible via Google Analytics, is there any service provider that has this kind of feature?
Note: I have gone through existing q/a but unable to find/figure out the solution.
I was able use another tracker Riveted, which by it's definition:
Riveted helps fix this by measuring the amount of time users are
actively engaged (e.g., clicking, scrolling, using the keyboard) and
then reporting the data to Google Analytics in frequent intervals.
More on it's page.
While Riveted is written with a direct global variable, we need to work around to make it available for the react project using exports-loader.
Here is what I could achieve:
Get the riveted.js locally as a file
Ensure to install the exports-loader via npm install exports-loader --save
Import the same with the location of revited.js as:
import riveted from 'exports-loader?exports=riveted!./riveted.js';
After you have initialised ReactGA.initialize(configs);
If you check the source code of riveted, you will notice it's using the same ga object of window.ga and thus the google analytics once initialised via ReactGA.initialize should be enough.
The react-ga provides an ability to extend ga. They state ga can be accessed via ReactGA.ga() method. This gives developers the flexibility of directly using ga.js features that have not yet been implemented in ReactGA. No validations will be done by ReactGA as it is being bypassed if this approach is used.
Then the ga allows writing a custom plugin
So with all that here is what the code looks like:
import React, { PureComponent } from 'react';
import ReactGA from '../../src';
import riveted from 'exports-loader?exports=riveted!./riveted.js';
export default class App extends PureComponent {
constructor(props, context) {
super(props, context);
this.state = {
reactGaInitialised: false,
configs: [DEFAULT_CONFIG]
};
}
initReactGA = (event) => {
const { configs } = this.state;
ReactGA.initialize(configs);
// Send initial test view
ReactGA.pageview('test-init-pageview');
function TrackerCustomPlugin() {
this.riveted = riveted;
}
TrackerCustomPlugin.prototype.init = riveted.init;
let ga = ReactGA.ga();
ga('provide', 'riveted', TrackerCustomPlugin);
ga('require', 'riveted');
ReactGA.plugin.execute('riveted', 'init', {
reportInterval: 10, // Default: 5
idleTimeout: 20, // Default: 30
nonInteraction: true // Default: true
});
};
Here is how the events are sent to GA from my local:
And the GA Dashboard showing Time Spent:

What is the best way to structure REST backend API calls with React?

Currently me and some colleagues are building a full stack web application, using React as our frontend framework. In this application, we need to perform CRUD operations on multiple resources, therefore multiple pages.
In my previous experience, I found tutorials/courses that put API calls in a services folder. Here's a simple example.
However, I realized this approach doesn't address loading/error states. So, I tried to come up with a solution using hooks, following another example I found: code.
This worked well for a feature I implemented, but I don't know how extensible it can be.
My question is, what is the better approach? Is there another one I didn't mention?
Reactjs is a library not a framework like Angular, there no one single approach how to handle your project structure. There are many alternatives, try to follow the good practices; if you are developing a big project that needs to scale use Redux as state management library, for me for a simple React project, we make folder called services and in an index file we prepare all our services :
/* root services ⚓️ .. */
import axios from 'axios';
const API_URL = 'http://yourapi.com/api/';
const headers = { 'Content-Type': 'application/json' };
const add = (data) => axios.post(`${API_URL}/form`, data, { headers });
const getData = () => axios.get(`${API_URL}/hotels`, { headers });
etc ...
export {
add,
getData
};
And for the call into Components
import { serviceName } from '../services/index';
serviceName({/*params if it's necessary */ })
.then(data => {
//---Get your Data
})
.catch(err => {
//---Handle your Api call error
});

Resources