easy enough right : )
-react app
-im using import TagManager from "react-gtm-module";
in root.js
useEffect(() => {
TagManager.initialize({ gtmId: gtmKey });
//..........
},[]);
i show gtm.js firing in the network tab on browser tools, this should mean i'm running
now in my component, trying to access data layer
const GTMSearchEvent = (v) => {
console.log(v);
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
"event": "search",
"searchQuery": v,
});
};
my param "v" is logging so the function is running, just not really able to see any event triggering
i cant seem to find anything in GTM or GA showing this event.
how can i finish implementing? just want to pass the search queries to my analytics/tag mgr
Setting up the dataLayer pushes is just half of the battle. You need to config your GTM container to "listen" for those events and variables.
Setup new variable to track search query (note that you need to name it exactly how you pushed it to the data layer.
Setup new trigger to track the data layer event
After that, you can do whatever you want/need to do. Here's a simple example if you want to capture it as an event (note, the names are arbitrary, pick something that makes sense to you, just note the variable name that I used for the label, you can use this anywhere within GTM.
Related
I'm trying to create a payment screen in React using Recurly.js. I'm using the official React library and am trying to hook into the set.plan event to retrieve plan information. I previously did this without issue using vanilla Recurly.js in Angular, but I haven't been able to do so in React and it's not clear to me if I'm doing something wrong or if there's a bug.
I adapted one of the Interactive Demo scenarios to demonstrate this. Please see the comments added in my sandbox:
const [{ price, loading }, setPricing, checkoutPricing] = useCheckoutPricing(
null,
setRecurlyError
);
useEffect(() => {
/*
Should this be called frequently? I know the price state gets updated, but I would not
expect to constantly receive a new/updated instance of checkoutPricing.
*/
console.log("checkoutPricing updated", checkoutPricing);
/*
This never gets called even after selecting a new plan in the dropdown menu
*/
checkoutPricing.on("set.plan", (plan) => {
console.log("plan updated", plan);
});
}, [checkoutPricing]);
Am I getting a new instance of checkoutPricing on each render? That might explain why my event is never firing, but I'm not sure how to avoid that.
I've been playing around with React and Azure App Insights.
const appInsights = useAppInsightsContext();
For Events and Metrics only, there seems to be 2 ways of doing things. Why is this? And why is it only for these 2 things only ie for PageViews or exceptions you can only use the second way (appInsights.trackPageView, appInsights.trackException)
//first way
const trackEventHook = useTrackEvent(
appInsights,
"AppInsightsPage Track Event Hook",
{ extraData: "some extra data important to this" },
false
);
trackEventHook({ extraData: "function call extra data" });
//2nd way
appInsights.trackEvent({ name: "AppInsightsPage Custom Event" }, undefined);
While using Application Insight, we use TrackEvent in our code to count various events. How often users choose a particular feature or maybe how often they make particular choices.
For Example, we want to understand the user behavior on a site and we want to know about specific actions like clicking the Add to Cart button.
This can be done by two ways :
Using trackEvent Method
appInsights.trackEvent({ name: 'EventName', properties: { anyProperty } })
We use appInsights object that we are exporting and pass some data to trackEvent, the name of the event we are tracking and any custom properties we want to include in the event.
Using React Plugin useTrackEvent Hook
const trackEventName = useTrackEvent(appInsights, "Event Name", condition);
The useTrackEvent Hook is used to track any custom event that an application may need to track, such as a button click or other API call. It takes four arguments:
Application Insights instance (which can be obtained from the useAppInsightsContext Hook).
Name for the event.
Event data object that encapsulates the changes that has to be tracked.
skipFirstRun (optional) flag to skip calling the trackEvent call on initialization. Default value is set to true.
trackExpection is used to log exception which are related to API, we don't know when they will happen and for trackPageView, page view telemetry is sent by default when each screen or page is loaded. So, in trackExpection and trackPageView we don't have any data object to track any changes. That's why we don't use useTrackEvent hook for this two.
For more information please check the following Microsoft Documents:
React Plugins for Application Insights.
Application Insight API.
Is there any way to pause firestore listener without removing it?
I have multiple firebase listeners, some are dependent on other, that changes or start other listeners on data change. Lets say my first listener starts a second listener its onSnapshot. First listener started on useEffect. For certain condition I may not want to change the second listener, so I need to discard data change update from first listener.
If condition met (button click), I discard data changes on first listener for a few moments. Currently I'm doing this using a boolean with useRef. My react app is working fine, with dependant listeners like this. I could remove the listener but I do not want to remove and recreate the listener.
I was wondering if there is a pausing mechanism or method available for any listener. I think it will save a tiny read cost if there was such a method because I'm not using that data sent onSnapshot.
Code example:
useEffect(() => {
let firstListener, secondListener;
//console.log("useEffect...");
function ListenerFunc(p) {
secondListener = await firestore
.collection("test")
.doc(p)
.onSnapshot((doc) => {
//console.log("Current data: ", doc.data());
//Need to discard unwanted change here.
//Changing it on button click for a 2 seconds then it changes back to : pauser.current = false.
if (pauser.current) {
console.log("paused for a moment.");
//pauser.current = false;
return;
}
else {
//update.
}
})
}
firstListener = firestore
.collection("test")
.doc("tab")
.onSnapshot((doc) => {
//console.log("Current data: ", doc.data());
var p = doc.data().p; //get variable p
ListenerFunc(p);
});
// cleanup.
}
Unfortunately this is not possible. If you need to stop listening for changes, even temporarily, you have to detach your listener and attach a new one when you want to start listening again, there is no pause mechanism for listeners.
You could open a Feature Request in Google's Issue Tracker if you'd like so that the product team can consider this, but given that this has already been proposed in this GitHub Feature Request for the IOS SDK and it was rejected I don't see this changing anytime soon.
I know Redux solves this but I came up with an idea.
Imagine I have an app that gets some JSON on start. Based on this JSON I'm setting up the environment, so let's assume the app starts and it downloads an array of list items.
Of course as I'm not using Redux (the app itself is quite simple and Redux feels like a huge overkill here) if I want to use these list items outside of my component I have to pass them down as props and then pass them as props again as deep as I want to use them.
Why can't I do something like this:
fetch(listItems)
.then(response => response.json())
.then(json => {
window.consts = json.list;
This way I can access my list anywhere in my app and even outside of React. Is it considered an anti-pattern? Of course the list items WON'T be changed EVER, so there is no interaction or change of state.
What I usually do when I have some static (but requested via API) data is a little service that acts kind like a global but is under a regular import:
// get-timezones.js
import { get } from '../services/request'
let fetching = false
let timez = null
export default () => {
// if we already got timezones, return it
if (timez) {
return new Promise((resolve) => resolve(timez))
}
// if we already fired a request, return its promise
if (fetching) {
return fetching
}
// first run, return request promise
// and populate timezones for caching
fetching = get('timezones').then((data) => {
timez = data
return timez
})
return fetching
}
And then in the view react component:
// some-view.js
getTimezones().then((timezones) => {
this.setState({ timezones })
})
This works in a way it will always return a promise but the first time it is called it will do the request to the API and get the data. Subsequent requests will use a cached variable (kinda like a global).
Your approach may have a few issues:
If react renders before this window.consts is populated you won't
be able to access it, react won't know it should re-render.
You seem to be doing this request even when the data won't be used.
The only downside of my approach is setting state asynchronously, it may lead to errors if the component is not mounted anymore.
From the React point of view:
You can pass the list from top level via Context and you can see docs here.
Sample of using it is simple and exists in many libraries, such as Material UI components using it to inject theme across all components.
From engineering concept of everything is a trade of:
If you feel that it's gonna take so much time, and you are not going to change it ever, so keep it simple, set it to window and document it. (For your self to not forget it and letting other people know why you did this.)
If you're absolutely certain they won't ever change, I think it's quite ok to store them in a global, especially if you need to access the data outside of React. You may want to use a different name, maybe something like "appNameConfig"..
Otherwise, React has a feature called Context, which can also be used for "deep provision" - Reference
My React App has a state called googleAccounts which is initially empty:
getInitialState() {
return {
value: '',
googleAccounts: {}
};
},
I have a simple search bar. When a search is performed, the server communicates with Google's API to get a list of accounts for that search, then googleAccounts is populated with accounts. This works wonderfully and the accounts are displayed below the search bar as search results.
searchGoogleAccounts(e){
e.preventDefault();
Client.getGoogleAccounts(this.state.value, (accounts) => {
this.setState({googleAccounts: accounts});
});
},
Then I want to take each account and send it to the Atlassian API to see if the account exists in the Atlassian database. I made a function that takes the account name and if there is an Atlassian account for that name it returns that account in JSON. This function also works fine.
I'm just not sure how I should use this function to properly interact with the DOM. If there is an Atlassian account I want to display a checkmark. If there is not an account I want to display a button to make the Atlassian account. And while it's waiting for a response from the Atlassian API I want to display a loading icon.
I tried adding an atlassian property to each of the googleAccounts. The problem with this approach was that I had to update the entire googleAccounts each time I grabbed an atlassian account. So separate calls would update googleAccounts at the same time and overwrite each other's changes. I thought about altering the DOM directly within the function but I read that this is considered insecure. I am not sure what my best option is and any advice would be appreciated.
You can pass an updater function to setState instead.
this.setState((prevState, props) => {
return {
googleAccounts: {
...prevState.googleAccounts,
[someGoogleAcctId]: {
...prevState.googleAccounts[someGoogleAcctId],
atlassian: resultOfAPICall
}
}
};
});
This way you aren't accessing this.state in multiple API callbacks, and instead you're always receiving the currently up-to-date state before altering it. Your callbacks were probably overwriting each other's changes because they were starting from the same original state snapshot, instead of taking the existing state changes into account (which you can't do if you're not using the updater functions, since you don't have access to the intermediate states).