Add React Hot Reloading to create-react-app

I love create-react-app. I’ve used it as the boilerplate generator for the last 4 projects I’ve worked on. I’ve tried other React boilerplates, but always come back because of it’s great foundation, as well as it’s ability to be ejected and customized.

One thing I miss dearly is hot reloading. React Hot Loader is, in my opinion, one of the killer features of React that makes it better/faster to develop with than any other front-end technology I’ve ever used. There’s no canonical way to add hot reloading into create-react-app, so here’s my method of adding it.

Note: In the next few days I’ll also go over how I add things like Sass, Redux, and react-router to create-react-app.

Another Note: This involves “ejecting” the app, and that’s an irreversible action. Be sure you want to eject before you actually do. Read more about ejecting create-react-app.

Alright, let’s do this.

Installation

  1. If you’re unfamiliar with create-react-app, you install it by running
    npm install -g create-react-app
  2. You create a new create-react-app by cd’ing to the correct folder, then running
    create-react-app my-app

Customization

Now that we’ve successfully installed and created our app, we can customize the configuration

  1. First, we need to eject the app so the webpack config is exposed and editable.
    npm run eject

    Reminder: This is very permanent.

  2. Install React Hot Loader by running
    npm install --save-dev react-hot-loader@next

    At the time of writing, this installed v3.0.0-beta.6

  3. In the package.json file, we need to add
    "plugins": [
    	"react-hot-loader/babel"
    ]

    so the babel object now reads:

    "babel": {
      "presets": [
        "react-app",
        "stage-1"
      ],
      "plugins": [
        "react-hot-loader/babel"
      ]
    },
  4. In the webpack.config.dev.js file, we need to add
    'react-hot-loader/patch'

    as the first entry point in module.exports.entry. It will now read

    module.exports = {
      ...
      entry: [
        'react-hot-loader/patch',
    ...
  5. In the index.html file, we need to add an import of AppContainer.
    import {AppContainer} from 'react-hot-loader';
  6. Then we need to change the default render function to be
    const rootEl = document.getElementById('root');
    
    ReactDOM.render(
        <AppContainer>
            <App />
        </AppContainer>,
      rootEl
    );
  7. Finally, we need to add in the call to the NextApp when App (or any child) is changed.
    if (module.hot) {
        module.hot.accept('./App', () => {
            const NextApp = require('./App').default; // eslint-disable-line global-require
            ReactDOM.render(
                <AppContainer>
                    <NextApp />
                </AppContainer>,
                rootEl
            );
        });
    }

Hit me up on Twitter if you have any questions, comments, or if you have a better/easier way to add hot reloading to create-react-app.

So You Want to Change the Gravity Forms Form Tag…

I had an interesting request from a client today. They use Pardot to integrate with the forms on their old website, and wanted to do the same with their new WordPress theme. We’re using the always spectacular Gravity Forms for the forms on the site.

I did the integrations, and we got an error.

The form enc type appears to be incompatible with our pardot form handler according to this article:
 
Wrong Enctype
Pardot form handlers can only be integrated with forms using an empty enctype attribute or an enctype of application/x-www-form-urlencoded. Pardot doesn't accept an enctype of multipart/form-data.

I didn’t realize (but now it makes perfect sense) that Gravity Forms defaults to enctype=”multipart/form-data”. I scoured the Gravity Forms settings, looking for a way to switch that to the correct enctype without any luck. I hit up a good friend of mine, Rob Harrell, on Twitter, asking if there was a way to edit the form. Thankfully, there is. He sent me this page about a filter a developer can use the edit the form tag output by Gravity Forms.

I added this code to the functions.php file to change the enctype of the form:

add_filter( 'gform_form_tag', 'form_tag', 10, 2 );
function form_tag( $form_tag, $form ) {
    if ( $form['id'] != 1 ) {
        //not the form whose tag you want to change, return the unchanged tag
        return $form_tag;
    }
    $form_tag = preg_replace( "|enctype='(.*?)'|", "enctype='application/x-www-form-urlencoded'", $form_tag );
    return $form_tag;
}

Breaking down that code:

//Enter the ID of the form you want to alter here:
if ( $form['id'] != 1 ) {

//Alter the 
tag however you like here: $form_tag = preg_replace( "|enctype='(.*?)'|", "enctype='application/x-www-form-urlencoded'", $form_tag ); //This can be just about any replacement you want, or you can just return a new string that is the new form tag return '

Pardot is picky about the form they integrate with, and thankfully the Gravity Forms developers made it possible to alter the <form> tag however we need to.

Change is Scary; The Future is Bright

After two awesome years, it’s time.

My last day at Lemonly will be this Friday, January 29th. That’s a hard thing for me to write. I’ve been at Lemonly since December 2013, two of the best years of my life. But as with all things in life, change is what keeps us scared and growing.

What’s next? I’m finally starting my own business. I’ve been doing contract front-end development, building anything from huge web apps to WordPress themes, for startups and agencies, part time, for almost 5 years. It’s been a very successful endeavor, and so it’s time to do it with 100% of my energy and focus. It means I’ll be giving up 8 hrs a day with some of my best friends in the world, but to stay scared, and to continue to grow, it’s a step I have to take.

I’m excited (and scared) for the change. I’m excited to work less, after 2 years of 60-hour weeks. I’m excited to get back to my neglected side projects. I’m excited to give Prestige the time it deserves. I’m excited to learn because I want to, not because I need to.

What does that mean for Lemonly? Not a whole lot. The team I have had the honor of helping build is extremely capable, and the interactive infographics created by the designers at Lemonly are in great hands.

What does that mean for you? Probably not a lot, unless you or your company is looking for a contract developer to help bolster your team. I’ll still be ranting on Twitter, blogging too infrequently, and speaking at conferences.

I’ve got availability starting in mid-late-February, so contact me right away!

Hopes and Goals for 2016

2015 was an awesome year. I accomplished so much, both personally and professionally, and laid the foundation for the next 3-5 years. To help carry that momentum into and through the next year, I’m setting some goals, writing them down here, and tracking my progress as often as I remember. Hold me accountable, OK?

Personal

  1. Give my wife the vacation she deserves

    I want to bring my wife on a long-awaited vacation to Hawaii or Cuba. I’ve worked too hard, for too long, and she’s taken up my slack. She deserves 2 weeks on a beach.

  2. Run a half-marathon

    I’ve run 3 times a week since August, and I’ve gone from being winded after a block, to running a 24-minute 5k. I’ve got plans started to go from 5k to 10k, and then from 10k to half-marathon. I’ve got until late October to get the plans finished.

  3. Lose the weight I’ve gained over the holidays

    I started 2015 at 260 lbs. I had lost 80 lbs. and was at 180 lbs. before Thanksgiving. Then Christmas cookies happened and I gained back 15 of those pounds. I want to be back down to a stable 180 as quickly as possible.

  4. Read to my daughters 5 nights a week

    This should be an easy goal to accomplish. They deserve my time, and I want to give it to them.

  5. Read or listen to 25 fiction books

    My time spent reading and/or listening to books slipped toward the end of 2015. I want to make it a priority again.

  6. Finish my basement bathroom

    I suck at this stuff, so the goal really should be “make enough money to hire the work done”.

  7. Shop responsibly

    This is going to be the year of, “Josh gives as much money as he can to companies that care about their employees, the environment, and social justice.” Sorry, Walmart.

  8. Be far less angry

    This goal is hard to quantify, and hard to verify, but it’s the year of a presidential election, and I could let my anger get out of control. But I resolve to laugh at Donald Trump rather than pull my already-receding hair out.

Professional

  1. Get back into speaking at conferences

    2013 was a year that I spoke at 20 conferences. 2014 had me speaking at 10. 2015 saw a very pedestrian 4 speaking engagements. This year, I’d like to (mostly) split the difference and speak at 10 conferences and meetups again.

  2. Write 26 blog posts

    I say this every year, and I fail every year. But like all starry-eyed dreamers, I’m 10000% sure this year is the year. *eye roll*

  3. Learn Angular 2

    2014 was the year of Angular 1.x and 2015 was focused on React. 2016 brings a new version of my favorite front-end MVC framework, which includes my most desired feature… server-side prerendering. Woo.

  4. Build two products for startups

    Kidblog first scratched this itch, and now, 5 startups later, there’s nothing I love more. I don’t expect that to change in 2016.

Missouri River, South Dakota

Two weekends ago, I had the pleasure of joining the other Lemonly employees in Okoboji, IA, for #LemonsAtTheLake, our annual company retreat.

The next weekend, I went diving on the Missouri River. In stark contrast to the active, crowded, fun atmosphere in Okoboji, we were beautifully isolated.

Missouri River, SD
White Swan Recreation Area, SD

Slack Chats Between Lemonly Devs Are Solid Gold

Sometimes our conversations in the Devs Slack channel amaze me. Sometimes they scare me. Still not sure what to make of this one. I really appreciate them not banning me from the channel for life.

Me:
http://salvattore.com/ No jquery dependency.
THE FUTURE IS NOW

Ryan:
-1 Not enough jQuery

Michael:
Someone should start a rap group for you called jQuery and cover J-Kwon songs, but use techy lyrics.

Me:
Baby girl be rubbin on me
Heard that I dispell the myth that jquery
is necessary, for proper code chemistry
Time to bury it in the framework cemetery,
and get with comtemporary use of my 2K DOM pessary

(silence)

Me:
I wish I would’ve posted that so someone else could see it.

Normalizing addEventListener and event Between Modern Browsers and IE9

Modern browsers make using event listeners very easy. The API is normalized across all modern browsers (Chrome, Firefox, Safari, IE10+, iOS, Android), but if you’re stuck supporting IE9 on a project like I am right now, some elbow grease is needed to make your event listeners work the same across browsers.

Functions/Snippets For IE9

//Add an event listener to an element
function listen(element, event, callback) {
    if(element.attachEvent) {
        element.attachEvent("on" + event, function() {callback.call(element);});
    } else if(this.addEventListener) {
        element.addEventListener(event, callback, false);
    }
}

//If you prefer adding this function to the element prototype, use this syntax
Element.prototype.listen = function(event, callback) {
    if(this.attachEvent) {
        this.attachEvent("on" + event, function() {callback.call(this);});
    } else if(this.addEventListener) {
        this.addEventListener(event, callback, false);
    }
};

//Doing this allows you to add it to the NodeList prototype too
NodeList.prototype.listen = function(event, callback) {
    for(var i = 0, l = this.length; i < l; i++) {
        this[i].listen(event, callback);
    }
};

Inside the callback function, some more work needs to be done:

function callback(event) {
    //Get the event in both IE9 and modern browsers
    var event = event ? event : window.event;
    
    //Get the target of the event (in listeners like click)
    var target = event ? event.target : window.event.srcElement;
}

Finally, you can use the event to stop propagation using this function:

function stopPropagation(event) {
    if(event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.returnValue = false;
    }
}

Calculating an Element’s Distance From the Top of the Document

For the times that I need to know how far an element is from the top of the DOM, not the top of it’s parent, I use this helper function.

//Loops through all parent nodes of an element to get it's distance from the top of the document
function getDistanceFromTop(element) {
    var yPos = 0;

    while(element) {
        yPos += (element.offsetTop);
        element = element.offsetParent;
    }

    return yPos;
}

This function returns the number of pixels the top of the element is from the top of the DOM.

Interviewing Recruiters

I get emails and messages from recruiters two or three times a week. On top of that, I help lead the local developer meetup, so I get contacted by recruiters to help introduce them to the appropriate developers for their open positions.

I don’t mind being contacted by recruiters, and if I can help them, I love to. I know enough developers that I can usually point them toward at least one prospect.

That said, I ask something in return. I’ve built a list of 11 questions that I ask them to answer before I pass the request on to developers in our community. Read More…

Wasted Moments, Missed Opportunities

You will only become yourself in the surrender to zero. Not zero things. Toys, people, friends, lovers, jobs, titles, commodities. A greater zero.

Zero moments wasted. On anything less than love, passion, dreams, suffering, nobility, greatness, wonder, grief, joy. Zero moments wasted. On anything less than what is incandescent, searing, unthinkable, laughable, hopeless, dangerously noble, impossible, daunting, unreasonably beautiful, senselessly noble.

Time isn’t wasting away. We are.

From Umair Haque’s essay, The Highest Score