<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sara Gibbons</title>
    <description>The latest articles on Forem by Sara Gibbons (@saragibby).</description>
    <link>https://forem.com/saragibby</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F21880%2Fb31c4a0d-106e-4308-b2e8-e3fbccab6637.jpeg</url>
      <title>Forem: Sara Gibbons</title>
      <link>https://forem.com/saragibby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/saragibby"/>
    <language>en</language>
    <item>
      <title>Server Side React + Google Analytics Event Tagging</title>
      <dc:creator>Sara Gibbons</dc:creator>
      <pubDate>Tue, 12 Nov 2019 23:16:42 +0000</pubDate>
      <link>https://forem.com/saragibby/server-side-react-google-analytics-event-tagging-44hb</link>
      <guid>https://forem.com/saragibby/server-side-react-google-analytics-event-tagging-44hb</guid>
      <description>&lt;p&gt;Often times whether you are working on client or server side rendered React it all feels the same. All the same familiar pieces and how you develop. It isn't until you hit a dark corner on a server side rendered (SSR) React app where you get a &lt;code&gt;window undefined&lt;/code&gt; message that you begin to question your life choices. Google Analytics event tagging is one of those dark corners. &lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Google Analytics Wired In
&lt;/h2&gt;

&lt;p&gt;Now, tracking page views to Google Analytics, pretty straight forward for an SSR React app. For those of you who haven't dug into that, here is the pieces that make that happen:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Just like the &lt;a href="https://developers.google.com/analytics/devguides/collection/gtagjs"&gt;docs say, "Add gtag.js to your site"&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This translates to somewhere incorporated into your app you will have something along the lines of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import Head from 'next/head';

import { GA_TRACKING_ID } from '../lib/gtag';

const Meta = () =&amp;gt; (
  &amp;lt;Head profile="http://www.w3.org/2005/10/profile"&amp;gt;
    &amp;lt;title key="title"&amp;gt;My Awesome Website Title&amp;lt;/title&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt;
    &amp;lt;meta charSet="utf-8" /&amp;gt;
    &amp;lt;link rel="icon" type="image/png" href="favicon.png" /&amp;gt;
    &amp;lt;meta
      name="description"
      content="The super neat description of my site"
    /&amp;gt;
    &amp;lt;meta
      name="keywords"
      content="saragibby, sara, gibby, who runs the world"
    /&amp;gt;

    &amp;lt;script
      async
      src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
    /&amp;gt;

    &amp;lt;script
      dangerouslySetInnerHTML={{
        __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${GA_TRACKING_ID}');
          `,
      }}
    /&amp;gt;
  &amp;lt;/Head&amp;gt;
);

export default Meta;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Where the value of &lt;code&gt;GA_TRACKING_ID&lt;/code&gt; is the tracking identifier assigned to your Analytics site. &lt;/p&gt;

&lt;p&gt;Once you have this baked in you are up and running. Each time this snippet renders it will send a pageview hit to the connected Google Analytics account. &lt;/p&gt;

&lt;p&gt;In the example above, I have this rendering as part of the layout of a page. Which means each time the layout is rendered a ding to the pageview hits. Which gives us our log of each pageview for the site. &lt;/p&gt;

&lt;p&gt;I haven't yet found many situations where this doesn't track a pageview as expected. I've read a couple of people recommend adding a trigger to Analytics when the route changes, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Router.events.on('routeChangeComplete', url =&amp;gt; gtag.pageview(url));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Test your site, see if you need it. Some people reference shallow rendered components, but I just care about the page anyway, the other intel I want is in the user behavior... the event tagging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's get those events tagging in Analytics
&lt;/h2&gt;

&lt;p&gt;You got Google Analytics tracking your page views, but now what you really want to know is things like "Which of the buttons gets the most clicks?"... "How many people click to 'show more'?" I know! I love all those juicy deets too! &lt;/p&gt;

&lt;p&gt;But Analytics isn't going to make this an easy journey for server-side rendered app. Now, you can pretty easily follow &lt;a href="https://developers.google.com/analytics/devguides/collection/gtagjs/events"&gt;the docs&lt;/a&gt; and get a client-side rendered up hooked up for event tagging. But, server-side, if you have tried before to log events you've most likely hit the "window undefined" error. Cause, well it is. You are on the server, there is no window at the time of render. &lt;/p&gt;

&lt;p&gt;If you have hit this in other areas of your application you most likely found you can get around this by using &lt;code&gt;componentDidMount&lt;/code&gt; to access the window. But add a &lt;code&gt;componentDidMount&lt;/code&gt; to each component you want to track events on so that you can et around the &lt;code&gt;window undefined&lt;/code&gt; error for Analytics, less than ideal.&lt;/p&gt;

&lt;p&gt;What you can do is add a a couple of functions that will trigger each other on a client side event. &lt;/p&gt;

&lt;p&gt;First piece, create a shared lib or util file for your Google Analytics functions (now this assumes you have Analytics wired into your app like above). You will most likely add to this file as your app grows, but to start it may just have this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// relative path to file: lib/gtag.js

export const event = ({ clientWindow, action, category, label, value }) =&amp;gt; {
  clientWindow.gtag('event', action, {
    event_category: category,
    event_label: label,
    value,
  });
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This gives you an &lt;code&gt;event&lt;/code&gt; function you can call, passing in the values you want to track for the given event. You can then import this function to the component that has the &lt;code&gt;onClick&lt;/code&gt; (or whatever other) event you want to add a tag in Analytics for. &lt;/p&gt;

&lt;p&gt;You'll see we pass in &lt;code&gt;clientWindow&lt;/code&gt; here as opposed to just getting &lt;code&gt;window&lt;/code&gt; within the function. We do this cause when the import happens during the server-side render, when &lt;code&gt;window&lt;/code&gt; will still be undefined. If we trigger this function on the client-side event the &lt;code&gt;window&lt;/code&gt; will exist and we can pass it in as an argument. &lt;/p&gt;

&lt;p&gt;Here is how that will look in your component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as gtag from '../../lib/gtag';

const CoolLink = ({ className, linkText }) =&amp;gt; {
  const clickTracking = e =&amp;gt; {
    gtag.event({
      clientWindow: window,
      action: 'click',
      category: 'link button',
      label: props.label,
    });
  };

  return (
    &amp;lt;a
      href={props.href}
      onClick={clickTracking}
      className={className}
    &amp;gt;
      {linkText}
    &amp;lt;/a&amp;gt;
  );
};

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;clickTracking&lt;/code&gt; function for &lt;code&gt;CoolLink&lt;/code&gt; is only fired for the client-side click event on the anchor tag. It sends the event tag to Analytics and then completes the default/expected behavior of the link. The best part &lt;code&gt;window&lt;/code&gt; is defined here! &lt;/p&gt;

&lt;p&gt;Now, one change can spoil the fun. Let's look close at this line &lt;code&gt;onClick={clickTracking}&lt;/code&gt;. Here the &lt;code&gt;clickTracking&lt;/code&gt; function is being passed in but &lt;em&gt;not&lt;/em&gt; evaluated. So when in renders on the server it is not evaluating the part of that function referencing &lt;code&gt;window&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you change this line to &lt;code&gt;onClick={clickTracking()}&lt;/code&gt;, with the added parens on the function, the function will evaluate on render of the component. In this case, that means it will render on the server, hit the call to &lt;code&gt;window&lt;/code&gt; and spit out the &lt;code&gt;window is undefined&lt;/code&gt; error. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sweet, but I need to pass an argument to my tracking function, halp!
&lt;/h2&gt;

&lt;p&gt;I got you. Here is what you need to do... change your &lt;code&gt;clickTracking&lt;/code&gt; function to take the arguments you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const clickTracking = (e, label) =&amp;gt; {
    gtag.event({
      clientWindow: window,
      action: 'click',
      category: 'link button',
      label: label,
    });
  };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You will still trigger this function &lt;code&gt;onClick&lt;/code&gt; but remember we don't want it to evaluate so we can't go with our instincts here to add on &lt;code&gt;onClick={clickTracking('newsletter')}&lt;/code&gt;. We still want to pass in a function that will evaluate &lt;code&gt;onClick&lt;/code&gt;, so that is exactly what we are going to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onClick={() =&amp;gt; clickTracking('newsletter')}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There you go, track your events, report on all the things and enjoy the server-side rendered goodness!&lt;/p&gt;

</description>
      <category>serversiderendering</category>
      <category>react</category>
      <category>analytics</category>
      <category>eventtagging</category>
    </item>
    <item>
      <title>Better Way To Embed Active Campaign Forms Into React</title>
      <dc:creator>Sara Gibbons</dc:creator>
      <pubDate>Mon, 04 Nov 2019 02:47:04 +0000</pubDate>
      <link>https://forem.com/saragibby/better-way-to-embed-active-campaign-forms-into-react-n9n</link>
      <guid>https://forem.com/saragibby/better-way-to-embed-active-campaign-forms-into-react-n9n</guid>
      <description>&lt;p&gt;Let's face it, embedding scripts in your React app just makes you feel like you need a shower. So when Active Campaign comes along with a form you embed you feel a lot of, "Get outta here!" Even better you have to build it to match a pre-defined style. Yeah, I feel ya. &lt;/p&gt;

&lt;p&gt;Realizing we have to deal with this beast we are left with 2 options after we create the form in Active Campaign:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Style the form within Active Campaign.
&lt;/h3&gt;

&lt;p&gt;This will most likely mean investing hours of your life fighting with the limited options and custom styles. Sure do able, but for most of us developers out there, this is super frustrating. As you are not just trying to make that more look decent, it needs to match your exact syles, and oh yeah render properly within your site. &lt;/p&gt;

&lt;p&gt;For those of you brave enough to travel this path, may the force be with you. If you do, here are my tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either use the form for just the form input and submit elements or for the entire form section you are working to build. No gray area here. Limited, or all in. &lt;/li&gt;
&lt;li&gt;Don't wait to dive into the custom styles. It's really the only way you are going to get anywhere. Get the tags set up that you need, stay organized and might against all urges to reach for the &lt;code&gt;!important&lt;/code&gt;... we all know that ends no place good. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you have your form ready, for the sake of organization give that thing its own React component. It will need to be a &lt;code&gt;React.Component&lt;/code&gt; so that you can utilize the &lt;code&gt;componentDidMount&lt;/code&gt; function. Here is where you will inject the Active Campaign provided script into the page. You will end up with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ActiveCampaignForm extends Component {
  componentDidMount() {
    const script = document.createElement('script');

    script.src = 'https://youareawesome.activehosted.com/f/embed.php?id=1';
    script.async = true;

    document.body.appendChild(script);
  }

  render() {
    &amp;lt;div className="_form_1" /&amp;gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above &lt;code&gt;script.src&lt;/code&gt; is the script provided by Active Campaign and the element rendered is a &lt;code&gt;div&lt;/code&gt; with the &lt;code&gt;id&lt;/code&gt; of your Active Campaign form you are embedding. &lt;/p&gt;

&lt;p&gt;If you try to style the &lt;code&gt;div&lt;/code&gt; or rendered &lt;code&gt;form&lt;/code&gt; here in your component. Good luck. When the form fully renders from the Active Campaign script it will overrule all you have here. It is custom styles within Active Campaign for nothing. &lt;/p&gt;

&lt;p&gt;Now, if your form is pretty basic, no super custom styling, this may be the perfect solution for you. Enjoy it while it lasts. This is also a decent solution to prove that you have all wired correctly in Active Campaign... list, emails, post-submit form, all that good stuff. Just don't get too attached if you have custom styling tasks in your future. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. Build your own form in React. Post to the URL of the Active Campaign form.
&lt;/h3&gt;

&lt;p&gt;Ok, now we are talking. Full control of your form and styling all within your component. Beyond that, you can keep the user within the experience of your site and not have to bounce then into Active Campaign. &lt;/p&gt;

&lt;p&gt;To do this, again, give this beast its own component. It will help with organization, writing tests, plus I like things to have one purpose. &lt;/p&gt;

&lt;p&gt;Now, Active Campaign is not going to give you what you need easily. But all the information you will need is baked into the block of "Full Embed" code that they provide. Within that look for the form, you will need the URL the form submits to as well as all the hidden inputs. Here is what this is going to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ActiveCampaignForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      formSubmitted: false,
    };

    this.onSubmit = this.onSubmit.bind(this);
  }

  onSubmit(event) {
    event.preventDefault();
    const data = new FormData(event.target);

    fetch('https://youareawesome.activehosted.com/proc.php', {
      method: 'POST',
      body: data,
      mode: 'no-cors',
    })
      .then(response =&amp;gt; {
        this.setState({ formSubmitted: true });
        setTimeout(() =&amp;gt; {
          this.setState({ formSubmitted: false });
        }, 5000);
      })
      .catch(error =&amp;gt; console.log('Request failed', error));
  }

  render() {
    const { formSubmitted } = this.state;

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;h5&amp;gt;Join our mailing list!&amp;lt;/p&amp;gt;

        { formSubmitted &amp;amp;&amp;amp; (
          &amp;lt;p&amp;gt;
            &amp;lt;strong&amp;gt;THANK YOU&amp;lt;/strong&amp;gt; for joining our mailing list!
            &amp;lt;br /&amp;gt;
            Check your inbox for a confirmation.
          &amp;lt;/p&amp;gt;
        )}

        { !formSubmitted &amp;amp;&amp;amp; (
          &amp;lt;form onSubmit={this.onSubmit}&amp;gt;
            &amp;lt;input type="hidden" name="u" value="1" /&amp;gt;
            &amp;lt;input type="hidden" name="f" value="1" /&amp;gt;
            &amp;lt;input type="hidden" name="s" /&amp;gt;
            &amp;lt;input type="hidden" name="c" value="0" /&amp;gt;
            &amp;lt;input type="hidden" name="m" value="0" /&amp;gt;
            &amp;lt;input type="hidden" name="act" value="sub" /&amp;gt;
            &amp;lt;input type="hidden" name="v" value="2" /&amp;gt;

            &amp;lt;input
              type="text"
              name="email"
              placeholder="ex: hello@youareawesome.com"
              required
            /&amp;gt;
            &amp;lt;input type="submit" value="Submit"&amp;gt;
          &amp;lt;/form&amp;gt;
        )}
      &amp;lt;/div&amp;gt;
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above, I simply built the form I wanted out exactly how I wanted it. Added an &lt;code&gt;onSubmit&lt;/code&gt; handler to submit the values entered and set it to send to the URL I found in the provided "Full Embed" code from Active Campaign. &lt;/p&gt;

&lt;p&gt;A few things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I hit a CORS issue that prevented the fetch from occurring. There may be other ways to solve this, I just reach for adding &lt;code&gt;mode: 'no-cors'&lt;/code&gt; to the fetch options to get passed that issue. &lt;/li&gt;
&lt;li&gt;I opted to add a state here to know if the form was submitted, &lt;code&gt;formSubmitted&lt;/code&gt;. I did this so that I could display a message to the user so that they knew their sign up was successful. &lt;/li&gt;
&lt;li&gt;The catch fo when an error occurs on the submit should really be more sophisticated than a &lt;code&gt;console.log&lt;/code&gt;, but hey, we all start somewhere. In my case I'm going to update this to &lt;code&gt;Sentry.captureException(error);&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you are off. You have the best of both worlds, a form you can easily and fully style exactly how you need to and the convenience of using an Active Campaign form tied to a list. &lt;/p&gt;

</description>
      <category>activecampaign</category>
      <category>react</category>
      <category>embed</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
