{"componentChunkName":"component---src-templates-tags-js","path":"/tags","webpackCompilationHash":"329948123daed8fecb50","result":{"pageContext":{"isCreatedByStatefulCreatePages":false,"posts":{"JAMStack":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"gatsby":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}},{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}},{"excerpt":"I was drawn to Gatsby out of my love for React, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as  was taking off. It was a challenge at first to…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.456286427976686%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABenOzxcwzP//EABcQAQEBAQAAAAAAAAAAAAAAAAABAgT/2gAIAQEAAQUC6JdNK20r/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAARECEiD/2gAIAQEABj8CFZJa/8QAGxAAAQQDAAAAAAAAAAAAAAAAAQARITEQQYH/2gAIAQEAAT8hf5dwCOJfqtnsv//aAAwDAQACAAMAAAAQOz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQIBAT8QVkz/xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhENH/2gAIAQEAAT8QkAKol+66ej2CJljY9c1tfD//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Gatsby loves to claim to produce the fastest sites around\"\n        title=\"Gatsby loves to claim to produce the fastest sites around\"\n        src=\"/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg\"\n        srcset=\"/static/d580489e8877a5a2439959d5d0b2b3cd/afcd2/gatsby-stickers.jpg 300w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/82472/gatsby-stickers.jpg 600w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg 1200w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I was drawn to <a href=\"https://www.gatsbyjs.org/\">Gatsby</a> out of my love for <a href=\"https://reactjs.org/\">React</a>, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as <code class=\"language-text\">create-react-app</code> was taking off. It was a challenge at first to learn the simplicity of proxying to get the front end to run concurrently with a <code class=\"language-text\">node</code> / <code class=\"language-text\">express</code> API. And yet, to get from that point to server-side rendering took a little more research and effort. It has been fun learning with and from the larger coding community. I could continue to enumerate the other technical issues I have encountered and solved, and yet some others I still have to learn, but note something important so far regarding my journey—it has been a <em>techinical-first-journey</em>, focused on knowledge and skill of the various langauges and libraries, necessary yes, but perhaps not primary. The last thing on mind has been <strong>SEO</strong>, <strong>accessbility</strong>, and <strong>security</strong>.</p>\n<h2 id=\"Setting-An-SEO-First-Mindset\"><a href=\"#Setting-An-SEO-First-Mindset\" aria-label=\"Setting An SEO First Mindset permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting An SEO-First Mindset</h2>\n<p>I’ll leave accessibility and then security future posts, but what has impressed me thus far in my dive into the <code class=\"language-text\">Gatbsy</code> ecosystem has been <strong>the ease to configure search engine optimization</strong>. In fact, you can create an architecture for your site or app that is SEO driven long before developing your UI. I want to walk you through the things I have learned so far in optimizing a Gatsby site for SEO right from the start.</p>\n<h3 id=\"Before-We-Begin\"><a href=\"#Before-We-Begin\" aria-label=\"Before We Begin permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><em>Before We Begin</em></h3>\n<p>You need to have some familiarity with Gatsby. To learn how to install the <code class=\"language-text\">gatbsy-cli</code> and create a new Gatsby project from one of the many Gatsby Starters, please consider <a href=\"https://www.gatsbyjs.org/tutorial/\">completing the Gatsby tutorial</a>.</p>\n<p>Otherwise, <a href=\"https://www.gatsbyjs.org/starters/?c=SEO&#x26;v=2\">pick a starter</a> from the SEO category, and open the SEO component or just use the <code class=\"language-text\">gatsby-starter-default</code> by running from the command line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  gatsby new seo-blog https://github.com/gatsbyjs/gatsby-starter-default</code></pre></div>\n<p>The SEO component is dependent upon <code class=\"language-text\">react-helmet</code>, if your starter does not come with SEO initialized be sure to add it. We also want to add some other features like sitemap, google analytics, and RSS feed, for syndication. Finally, we need to create <code class=\"language-text\">robots.txt</code> to manage how search engines crawl the site. I’ve split up the commands below for spacing purposes, but they can all run as one <code class=\"language-text\">yarn add</code> command:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> react-helmet gatsby-plugin-react-helmet \n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-feed gatsby-plugin-google-analytics gatsby-plugin-sitemap\n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-robots-txt</code></pre></div>\n<p>With your starter and these plugins installed, we are ready to set up our site for SEO Performance.</p>\n<h3 id=\"Setting-up-gatsby-configjs\"><a href=\"#Setting-up-gatsby-configjs\" aria-label=\"Setting up gatsby configjs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting up <code class=\"language-text\">gatsby-config.js</code></h3>\n<p>Within the root of your new Gatsby project sits the file Gatsby uses to configure  <code class=\"language-text\">siteMetaData</code> and <code class=\"language-text\">plugins</code> and <a href=\"https://www.gatsbyjs.org/docs/gatsby-config/\">several other important features</a>.</p>\n<p>This file, <code class=\"language-text\">gatsby-config.js</code> is going to do the heavy lifting of importing all your vital SEO related content into GraphQL or create necessary files directly (like <code class=\"language-text\">robots.txt</code>).</p>\n<h4 id=\"Site-Metadata\"><a href=\"#Site-Metadata\" aria-label=\"Site Metadata permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Site Metadata</h4>\n<p>Metadata is as it sounds, data that extends across or throughout the entirity of your site. It can be used anywhere, but will come most in handy when configuring your SEO component as well as Google Structured Data.</p>\n<p>Initialize your metadata as an Object literal with key/value pairs that can be converted into <code class=\"language-text\">&lt;meta&gt;</code> tags, or can be passed to sitemaps or footers, wherever you might need global site data: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\">  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>title<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site will blow your mind with radical content, extravagant colors, and hip designs.<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span></code></pre></div>\n<p>Here is where you need to plan what might use across your site:</p>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> title</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> description</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> keywords</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> site verification</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> social links</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" disabled> other</li>\n</ul>\n<p>With <code class=\"language-text\">siteMetadata</code> set up, your can now query this data to be used within your plugin initialization, even within the same <code class=\"language-text\">gatsby-config.js</code> file. I’ve organized my <code class=\"language-text\">siteMetadata</code> so that I can make the following query:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    site {\n      siteMetadata {\n        title\n        description\n        author\n        siteUrl\n        siteVerification {\n          google\n          bing\n        }\n        social {\n          twitter\n        }\n        socialLinks {\n          twitter\n          linkedin\n          facebook\n          stackOverflow\n          github\n          instagram\n          pinterest\n          youtube\n          email\n          phone\n          fax\n          address\n        }\n        keywords\n        organization {\n          name\n          url\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span></code></pre></div>\n<p>This query returns an object matching this query structure:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  site<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      title<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      description<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      author<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteUrl<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteVerification<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        google<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        bing<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      social<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      socialLinks<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        linkedin<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        facebook<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        stackOverflow<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        github<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        instagram<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        pinterest<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        youtube<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        email<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        phone<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        fax<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        address<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      keywords<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>String<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n      organization<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        name<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        url<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h4 id=\"Plugin-Setup\"><a href=\"#Plugin-Setup\" aria-label=\"Plugin Setup permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Plugin Setup</h4>\n<p>We are going to focus on four plugins, each for the sitemap, RSS feed, robots.txt file, and Google Analytics (for tracking the SEO success of your site). We’ll initialize the plugins immediately following <code class=\"language-text\">siteMetaData</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/** SEE ABOVE **/</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span> </span><span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">/** An ARRAY **/</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> </span>  <span class=\"token punctuation\">}</span></code></pre></div>\n<ol>\n<li><strong>gatsby-plugin-sitemap</strong></li>\n</ol>\n<p>The sitemap plugin can be used simply or with options. Generally, you want to include anything and everything with high quality content, and <strong><em>exclude duplicate content, thin content, or pages behind authentication</em></strong>. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/creating-a-sitemap/\">detailed walkthrough for setting up your sitemap</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-sitemap</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">          exclude<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/admin</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/tags/links</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">]</span></span>        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span></code></pre></div>\n<ol start=\"2\">\n<li><strong>gatsby-plugin-feed</strong></li>\n</ol>\n<p><strong><em>An RSS feed helps with syndication of content on your site, like if you had a blog and wanted to cross-post to another better established blog, and it helps communicate changes to your site to search engines.</em></strong> This plugin allows you to create any number of different feeds utlizing the power of GraphQL to query your data. Some of what is below is dependent on how you structure your pages and posts in <code class=\"language-text\">gatsby-node.js</code>. The feed will walk through each of your pages in <code class=\"language-text\">markdown</code> generate an XML RSS Feed. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/adding-an-rss-feed/\">detailed walkthrough for adding an RSS feed</a>. </p>\n<p><strong><em>Note particularly the use of queries below to complete the feed.</em></strong></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">// graphQL query to get siteMetadata</span></span><span class=\"gatsby-highlight-code-line\">      query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">        {</span><span class=\"gatsby-highlight-code-line\">          site {</span><span class=\"gatsby-highlight-code-line\">            siteMetadata {</span><span class=\"gatsby-highlight-code-line\">              title</span><span class=\"gatsby-highlight-code-line\">              description</span><span class=\"gatsby-highlight-code-line\">              siteUrl</span><span class=\"gatsby-highlight-code-line\">              site_url: siteUrl,</span><span class=\"gatsby-highlight-code-line\">              author</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">        }</span><span class=\"gatsby-highlight-code-line\">      </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>      feeds<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token comment\">// an array of feeds, I just have one below</span>\n        <span class=\"token punctuation\">{</span>\n          <span class=\"token function-variable function\">serialize</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> query<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> site<span class=\"token punctuation\">,</span> allMarkdownRemark <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> siteMetadata <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> siteUrl <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> site<span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">return</span> allMarkdownRemark<span class=\"token punctuation\">.</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">edge</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n              <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> \n                node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> \n                  frontmatter<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                    title<span class=\"token punctuation\">,</span> \n                    date<span class=\"token punctuation\">,</span> \n                    path<span class=\"token punctuation\">,</span> \n                    author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> name<span class=\"token punctuation\">,</span> email <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featured<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> publicURL <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featuredAlt\n                  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                  excerpt<span class=\"token punctuation\">,</span> \n                  html\n                <span class=\"token punctuation\">}</span> \n              <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> edge<span class=\"token punctuation\">;</span>\n              <span class=\"token keyword\">return</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">assign</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> edge<span class=\"token punctuation\">.</span>node<span class=\"token punctuation\">.</span>frontmatter<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n                language<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">en-us</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                title<span class=\"token punctuation\">,</span>\n                description<span class=\"token punctuation\">:</span> excerpt<span class=\"token punctuation\">,</span>\n                date<span class=\"token punctuation\">,</span>\n                url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                guid<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                author<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>email<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> ( </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>name<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> )</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                image<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                  url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> publicURL<span class=\"token punctuation\">,</span>\n                  title<span class=\"token punctuation\">:</span> featuredAlt<span class=\"token punctuation\">,</span>\n                  link<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                custom_elements<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> <span class=\"token string\">\"content:encoded\"</span><span class=\"token punctuation\">:</span> html <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n              <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token comment\">// query to get blog post data</span></span><span class=\"gatsby-highlight-code-line\">          query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">          {</span><span class=\"gatsby-highlight-code-line\">            allMarkdownRemark(</span><span class=\"gatsby-highlight-code-line\">              sort: { order: DESC, fields: [frontmatter___date] },</span><span class=\"gatsby-highlight-code-line\">            ) {</span><span class=\"gatsby-highlight-code-line\">              edges {</span><span class=\"gatsby-highlight-code-line\">                node {</span><span class=\"gatsby-highlight-code-line\">                  excerpt</span><span class=\"gatsby-highlight-code-line\">                  html</span><span class=\"gatsby-highlight-code-line\">                  frontmatter {</span><span class=\"gatsby-highlight-code-line\">                    path</span><span class=\"gatsby-highlight-code-line\">                    date</span><span class=\"gatsby-highlight-code-line\">                    title</span><span class=\"gatsby-highlight-code-line\">                    featured {</span><span class=\"gatsby-highlight-code-line\">                      publicURL</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                    featuredAlt</span><span class=\"gatsby-highlight-code-line\">                    author {</span><span class=\"gatsby-highlight-code-line\">                      name</span><span class=\"gatsby-highlight-code-line\">                      email</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                  }</span><span class=\"gatsby-highlight-code-line\">                }</span><span class=\"gatsby-highlight-code-line\">              }</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">          </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>          output<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/rss.xml\"</span><span class=\"token punctuation\">,</span>\n          title<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">My Awesome Site | RSS Feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li><strong>gatsby-plugin-robots-txt</strong></li>\n</ol>\n<p>With <code class=\"language-text\">robots.txt</code> files, you can instruct crawlers to ignore your site and/or individual paths, based on certain conditions. <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-robots-txt/?=robots\">See the plugin description for more detailed use cases</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token string\">'gatsby-plugin-robots-txt'</span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      policy<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> userAgent<span class=\"token punctuation\">:</span> <span class=\"token string\">'*'</span><span class=\"token punctuation\">,</span> allow<span class=\"token punctuation\">:</span> <span class=\"token string\">'/'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span></span>    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"4\">\n<li><strong>gatsby-plugin-google-analytics</strong></li>\n</ol>\n<p>Google analytics will help you track how users find and interact with your site, so you can manage and update your site over time for better SEO results. Verify your site with Google and store your analytics key here:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-google-analytics</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      trackingId<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<h3 id=\"Optimizing-the-SEO-Component\"><a href=\"#Optimizing-the-SEO-Component\" aria-label=\"Optimizing the SEO Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing the SEO Component</h3>\n<p>The secret sauce behind the SEO Component is the well-known <code class=\"language-text\">react-hemlet</code> package. Every page and every template imports the SEO Component and thus you can pass specific information to adjust the metadata for each public facing page.</p>\n<p>Use your imagination—what can you pass to this component to create the perfect SEO enabled page? Is the page a landing page, a blog post, a media gallery, a video, a professional profile, a product? There are 614 types of schemas listed on <a href=\"https://schema.org/docs/schemas.html\">https://schema.org</a>. You can pass specific schema related information to the SEO component.</p>\n<p>If any of these values you pass to the component, a <code class=\"language-text\">StaticQuery</code> would fill in what’s missing with <code class=\"language-text\">siteMetaData</code>. From this data, <code class=\"language-text\">react-helmet</code> creates all the <code class=\"language-text\">&lt;meta&gt;</code> tags, including <code class=\"language-text\">open graph</code> and <code class=\"language-text\">twitter</code> card tags, and pass relevant data to another component that returns <code class=\"language-text\">Google Structured Data</code>.</p>\n<p>Rather than including a long code-snippet, refer back to the <a href=\"#Before-We-Begin\">Before We Begin</a> section, or <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-react-helmet/\">refer to the <code class=\"language-text\">gatsby-plugin-react-helment</code> page for installation</a>. But please note, the structure of my SEO Component follows that outlined by <a href=\"https://blog.dustinschau.com/search-engine-optimization-with-gatsby\">this excellent post</a> by Dustin Schau.</p>\n<p>As I have tinkered with the SEO Component, here are the features I added:</p>\n<ol>\n<li>Additional Fields Passed to Component to:  distinguish between types of pages, such as blog posts, to handle authors of content other than main site author, and to handle changes in date modified for pages and posts. More could be added in the future.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    description<span class=\"token punctuation\">,</span>\n    lang<span class=\"token punctuation\">,</span>\n    meta<span class=\"token punctuation\">,</span>\n    keywords<span class=\"token punctuation\">,</span>\n    image<span class=\"token punctuation\">,</span>\n    title<span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// highlight start</span>\n    pathname<span class=\"token punctuation\">,</span>\n    isBlogPost<span class=\"token punctuation\">,</span>\n    author<span class=\"token punctuation\">,</span>\n    datePublished <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    dateModified <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span>\n    <span class=\"token comment\">// highlight-end</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></code></pre></div>\n<ol start=\"2\">\n<li>Setting <code class=\"language-text\">og:type</code> conditionally</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    property<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">og:type</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> isBlogPost <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">article</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">website</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </code></pre></div>\n<ol start=\"3\">\n<li>Always setting an <code class=\"language-text\">alt</code> property on the image object</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\">  <span class=\"token comment\">// ALWAYS ADD IMAGE:ALT</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span></code></pre></div>\n<ol start=\"4\">\n<li>Handling Secure Images</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token comment\">// handle Secure Image</span></span><span class=\"gatsby-highlight-code-line\">    metaImage <span class=\"token operator\">&amp;&amp;</span> metaImage<span class=\"token punctuation\">.</span><span class=\"token function\">indexOf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"https\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token operator\">-</span><span class=\"token number\">1</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">?</span> <span class=\"token punctuation\">[</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">            property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:secure_url\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">            content<span class=\"token punctuation\">:</span> metaImage<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span> property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:secure_url\"</span><span class=\"token punctuation\">,</span> content<span class=\"token punctuation\">:</span> metaImage <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token punctuation\">]</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span>  <span class=\"token punctuation\">)</span></code></pre></div>\n<ol start=\"5\">\n<li>Adding a Component to handle <code class=\"language-text\">Google Structured Data</code> using <a href=\"https://schema.org\">schema.org</a> categories. I came across an example of such a component from reading through various documentation and articles, I can’t recall where I saw the link first, but I borrowed and adapted <a href=\"https://github.com/jlengstorf/gatsby-theme-jason-blog/blob/e6d25ca927afdc75c759e611d4ba6ba086452bb8/src/components/SEO/SchemaOrg.js\">from Jason Lengstorf</a>. I made two small adaptations to his excellent work.</li>\n</ol>\n<h3 id=\"Configuring-the-SchemaOrg-Component\"><a href=\"#Configuring-the-SchemaOrg-Component\" aria-label=\"Configuring the SchemaOrg Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Configuring the SchemaOrg Component</h3>\n<p>You will import and call the <code class=\"language-text\">SchemaOrg</code> Component from within the <code class=\"language-text\">SEO</code> Component and place it just after the closing tag of the <code class=\"language-text\">Helmet</code> Component and pass the following properties:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token operator\">...</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">...</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Fragment Shorthand */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">&lt;</span>Helmet \n          <span class=\"token punctuation\">{</span><span class=\"token comment\">/* All the Meta Tag Configuration */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>SchemaOrg</span><span class=\"gatsby-highlight-code-line\">          isBlogPost<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          url<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          title<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          image<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaImage<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          description<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaDescription<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          datePublished<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>datePublished<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          dateModified<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>dateModified<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          canonicalUrl<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>siteUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          author<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost <span class=\"token operator\">?</span> author <span class=\"token punctuation\">:</span> siteMetadata<span class=\"token punctuation\">.</span>author<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          organization<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>organization<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          defaultTitle<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>I won’t copy and paste the entire <code class=\"language-text\">SchemaOrg</code> Component here. Grab it from the link above, and give Jason Lengstorf some credit in your code. Below are the few additions I made:</p>\n<ol>\n<li>I added author email to the Schema. This will come from <code class=\"language-text\">siteMetadata</code> for most pages and from post <code class=\"language-text\">frontmatter</code> from blog posts. This will support multiple authors for your site and each page can reflect that uniquely if you so choose.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Person\"</span><span class=\"token punctuation\">,</span>\n    name<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    email<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>email<span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"2\">\n<li>I updated the organization logo from a simple URI to an <code class=\"language-text\">ImageObject</code> type. While the <code class=\"language-text\">String</code> URI is acceptable to the <code class=\"language-text\">Organization</code> type, Google has specific expectations and was throwing an error until I changed it to an <code class=\"language-text\">ImageObject</code>. </li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  publisher<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Organization\"</span><span class=\"token punctuation\">,</span>\n    url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    logo<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"ImageObject\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      width<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>width<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      height<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>height<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span>    name<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li>Add <code class=\"language-text\">dataModified</code> to reflect changes to the page after initial publication for the <code class=\"language-text\">BlogPosting</code> type.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  datePublished<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">  dateModified<span class=\"token punctuation\">,</span></span></code></pre></div>\n<p>When you have more complexity within you site, you can pass flags to this Component to return differing types of schema as needed. But no matter what you do, do not put your site into production without first passing through the <code class=\"language-text\">script</code> generated by the component to the <a href=\"https://search.google.com/structured-data/testing-tool/u/0/\">Google Structured Data Testing Tool</a>.</p>\n<h2 id=\"Concluding-Thoughts\"><a href=\"#Concluding-Thoughts\" aria-label=\"Concluding Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Concluding Thoughts</h2>\n<p>When I configured my site according to the plan I outlined above, not only do I get image rich, descriptive Social Sharing cards, I get perfect SEO scores when running a Lighthouse Audit on my site:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 816px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 17.15686274509804%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAmUlEQVQI1z2N2w6CMBBE+f+/88H4YGJURAEpvdDL0lLGdo1OMtmzmexss+87qiYn8bYzc9wSWtVj3SLvs9eQxVUhEh5qwJq+mbQeiydmIkLzK7yMLZuPVsLhfoIj/89uU8fsY8CxO/PTqqsY0UnB7JxDU6GW2sWyq1JMUFKVGTkzxpRsQc4ZIQRorWHLM1OKxNBDPF/wpaxmH1t76BizOlMxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        title=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        src=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n        srcset=\"/static/384cdb474a81538eeda376637170d853/135ae/lighthouse_audit_seo.png 300w,\n/static/384cdb474a81538eeda376637170d853/34e8a/lighthouse_audit_seo.png 600w,\n/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png 816w\"\n        sizes=\"(max-width: 816px) 100vw, 816px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You also see that I scored 100% for Accessibility on my site. This is so easy to score with Gatsby as well, and I’ll talk about what I learned on this topic in the future.</p>\n<p>Cross-Posted: <a href=\"https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g\">https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g</a></p>","id":"fc7a6836-1cdc-519e-8c65-39beae2150c8","timeToRead":10,"frontmatter":{"date":"2019-04-20","path":"/blog/seo-accessibility-first-gatsby.html","tags":["gatsby","development","seo"],"title":"Putting SEO First with Gatsby","featuredAlt":"Gatsby loves to claim to produce the fastest sites around","redirect_from":null}},{"excerpt":"This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwACBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHjYtEUEP8A/8QAGxAAAgMAAwAAAAAAAAAAAAAAAQIAERIDBCH/2gAIAQEAAQUCtb62WVlzCcjj8WyZ/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEDAQE/ATF//8QAFxEBAAMAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAgEBPwGIDlf/xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIRITFh/9oACAEBAAY/AuNk04q/Sm9MwlRbP//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExUUH/2gAIAQEAAT8hK1J4EshDT4l0DhmIJu5HcwQi2y1n/9oADAMBAAIAAwAAABAcH//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxBLqL//xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAgBAgEBPxABX//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQWFRocH/2gAIAQEAAT8QWJfQg8dr6ioJ1ByR+k52ZRsu3UZ2ib0vEZnkR7jlCrVn/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Code displayed on a computer\"\n        title=\"Code displayed on a computer\"\n        src=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n        srcset=\"/static/41ced244a3d93044daa17132fdbf446a/afcd2/batman-coder.jpg 300w,\n/static/41ced244a3d93044daa17132fdbf446a/82472/batman-coder.jpg 600w,\n/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I was still hopeful, dreaming, a little naïve, yet expecting great things. I was ready to go to work and code hard! But that site did little more than highlight some of my work, projects that were good but not production quality. The page was overcoded - a single page with five sections but templated via <code class=\"language-text\">handlebars.js</code> (I should have been serving a single html file... <img class=\"emoji-icon\" alt=\"emoji-unamused\" data-icon=\"emoji-unamused\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAULUlEQVR4Ae2bBZAcR7auv5NZ1TCkIWkEHrGM1w5bqzVbZlhm3r3MjMvMcBn2MpuWmZkNWjPbAq9wmHqaqjLP6+rOuOrokMao9aMT+iOzqep8f57srKzW8P/j/+n4//H/QzjG8XYwr341GyPlVAyniLBZYKWx0o/SBYBQ9k5nFQ6p8hCeu1PhzquvZhfgj6kBbz820LL7NZypwnNjyxUmlpNtbLpMzmByghgB2+G9U9Qrvp7J4xJf9onekzi+KspnN/w3NwH6v3UF7HgOXUP9vNRYfjFXMOfZojGmy2LyGbgixiNWGxKQjlOroi6ToN7g64KveXzZ4Sre16v+B97xb1OzfBQoP2kGNJJ+wrGwQLR+lFdHsfxRrmh+xvZGmG6DLSgm9kg+hyn2Y/tWQ/cKpGslkutBTA4A9XW0XkLLh2BxHDd/AF+ZRWt1fGJwVcEvetxCSr3i70oT/bM9e7kaSJ+wAd+6iCcUq1dzZiHmvYUee2m0LCLqs0jeYQoRUf8oZuUZmJGnIT2bkcIgRF0gFoS2ihZQQB2kZbQ6jZYewo/9GH/oVtLZvfhqitYs6bwjnUupltw3qglvBG56Qgbc/0oeV5xwLbLrVfxhoUvekRuIu21/3GDzmK6IaORU7LorMMvPhOJggEsBDxqgBVCO0BfAgEQgQGUaP3ET7uGvko7diS+npGWDm02ozySL1bK+beM1/DmgP63vANnxEvqWF/nbQq99dTycI1pmsUVHtOJ47OYXYVacDVEBtA7qEDE8nlD1oVpykFbx4zfgHvoE6fgDuIolnXMkk3WqC+7qiQq/ve1jzAN6LA2QW57LqsFBrulaFl0Uj+SIeoWop9FuuhKz/kVIvh98FQEQeXxnUzqdQAFMAa3N4vc0TNj5FdJSnXRBScbqlOfSb09P86qtn+UgoE++AQF+eJBPF4bip+eX57G9EA0MEJ30CszIBaAJggeRJ3eN0XYjDEiMH/se6b3Xkc7M4BagNlGjOpXcPDnN8x+LCdGjhf/ylQw04K9rwq/M4IV4YIjolF9CBk5C3BwgIIBybAwARAHKmBVnEse9yN3/CnaKvM0DPH2Y5LpGri+46ivMAPpkGCCAOXElf10YiLbnV+SxfaYB30900mswfeshmQEx7fDHzAAAFMRVkMa5o5NfA/f+J8gseZ8Hr9tP1PSvgZ8DPKCP34AA/8Cr+cNin31VvCJH1G+JehvtxmchPaOQzrbg9YkDP2ZD0mozhywXHvg4Qh3vcxRTfdUDr3a3H381f/5IJsgjwf/wJTxt/YB8s7Cm0J1bnifqg2j0fMyay4AURBAA4acbGqhUgQi//+uke79POg/17Ptgf3Vxz4xecu7H+PFSJkRLwb9mhMKaXj6UH4q744GYqMdgB1Zihs8AvwgoEuifCgMEbfEjzZxsaRf4Q2gao1XXvSatf6jB8Mz/HqNKMOExGfCmy3hZscdujxrwtifGFA1m6GfAGnDlFrwIT2WIBhNshBk6FS1PYFMhGnAUF932N13mXvbf1/DfgD46AwL8G86krzsvr23C9zZUEEzPcPM6HldCREGfgpE/WiV4QbpGmjnaZALfGzdN6C75177hTP3M+25irs2EJQ0wgH3FZl6U77MnRH0RpthQ3iA9a0AU8eWlR/6pqgSJmjma8lQz5yz3fF96wis2py9qGPCfAd4tZYBkOmuQfG9Bfinqs5juCFswSD6PFJYhvgL48M6wrzfBjNSDV45pGIHIAIBXcAqaCYQEshzzeWxSw3dHZAy98+6XzhrU62+cxgVGXcoA+/7tbC12yTbbE2EKFpMzSK6ImAhcBWJpyOAWE8YmFplfqBNHhpUruukeLEDiwT3JRtjWORenqxwaXyRJPX29OUaWd2O749Y5E23mmOVqckkz94yh2JVse/923Xrxp/kR4JcywAB2pMc8N+6xzZsZNmeRyECUB3FQUCYPlvjKt37CTbceZHKiRK2WYozQ01fgrK1rePkLjmdZfx4Sz5MSsWFutsb1n3qAG2/ZT2m+ivdKPh8xvLyHM89YxZUXr2V4VQ9UfTPXLOcsd9dgyFhGengu+JsAB/gjGSCA2ThAXCzoxdK8k2OR2CCRYOIYTJ0vf+lhrv3EA0yNV+jKQV+PpW9ZjHOe+ekSH/v4/dx250He9fozGR7Mg9MnthuywuR4jbe8/yYevH+e4X7o78thraFeTTiwe4pr75/iK9/cyStfdDxXXbqumauPpJl7xpCxFAvpxRnbrhnS9mlgOg1429PYmC/ICbZokZzFNA2wYBz/dvXd/NWHbyct17jwik388huu5A//7KW89s9f1tTvvfcFvOQXn8ZUxbDjjkmwKfgauCq4MqQlSBcgmYdkFpKZTKE/33otLbXe66qtz9o0O1Z2zOaxs3OE8zXPneWQ5ZLllOWW5YhxSBRyz1kylowpYwvMcrQKsKO9nBrlTdHkDSZz0TZUiPjo5w9w7ccm2LptOa/8rbM5/ZQhqC9COUs6BRE2L89xzrbNvOJn1xFNH4K5faAe1AHa6qNHucCXw62Y0FqoGbZfsIxzn3cJfV0xVKpQnQRV6I04ZX0fV15xAbfdfTLX/t0NjRx30hMv56XP6EVqrsmQsWRMo73+VOCBpQww/UVzss0LEmfwBlOw3Pdgjf/4xATbr1jN77/+bPr8Ijx0N3gXAFPwSavF0Zcz4IHUdyyXnf2jXeOmoZuAKl2VChw8BHUPWJAITNxqxYCxnD46yMYPXsBfvv+GRq4HOG1zjhPXWmTRNFkypowN/KeOZoDJlI90k0SmBR8JiuHqz0+x4eRl/NFrj6N7+kFYSMAKqGsJbWMyUAckjOATvVktgANSbcGiQNIynHAOZ2HvAn29cTPH104sNnKe5V2/uTxUsSFjykfpJgJnpwESZGNhBZE0AaPIsHcsZfe08o53rKV7dg7m6mAEHG2jK8f+5xaRo9wkcUAKAHM1urXOH/z+Wt72tp3sH0s5rsdQtwKR0GQD28arpiPt2Eb0h/v2IFAT4Rd+dZTN/Q5mM3jTcSc3SMKhY4GctFrzJO9/DRC1nSMiYIAqYAw6V89ybeZcDQyIkDFlbEC85HeAEQpiQIAkVTasjtm8zKKTFRABPUwtQgAVXMUzOeOYnE1JHHQVDKMrI4p9BuoK+kQugAQSpTTvGJt2lMoeIzA8ELFqRQQWSBVVQKSZ62UnFUnnYpLpFAHEQMZ2tFVAQmuajOhh06spmpZRQEQDuyJ5AQ/3P1jjB7dVuPuhGhPTKUmiaCsTenotz7+kh2c3hHsEE6RjwE1rlOenE264s9ZYCivs2V9nsexxHghQJ27M8ysv7Gf1SIRP2k4wWcY4jwMAlDBgwYAgjTpmlHGeKg40LF/eC6IW2ipd8vDQroT//vwCd9xXQ7ynv8sw1CPkewURIfUwu+j454/O0NUFl1xQRGuKPIpilxjSFD71hTJf+GaJ6emU7pww2GtY0ydYC6pQTZS77qnw5yXHO39riGJO8G0rrTqHakPeg4MmGxjCMB5xL5B65tV71KUNCWgwQ0AQxMJXv1vhL64pUcgLmzbHDA1YSDyVCUd3HuIIFFhWFCKB7+5YbBhgELtEFUhojDC74HnP35W45Z6EDaMRZ2wt0l0UKlMOqbpmXwykTujJG/aMJdz/cIUzTsqhdUA1OODBJYHFk7EtdT9AAWopk03HfOaeQb1B8BCGv1pX6gPCn7xnkJO2RPT1QGwFZ5Uff7fKN/9rkUIsTROsgd68oKqoqRMMWDosTCwqZz4rzy+8vpc1I5ZCDGKF6Tnlk3+zwNyehL4+Q86C90oxEmo4kDqoQKBRrw25wOKbbEfbDWoQc3V5eHWiqFPw4SLHC2oApQn27PMN2AQWqjAbPhrB+WdHHNwTccuXE/p7hSTNDIPLLrNIsQ7lJZZID4TB27LJsGWrgXIFZhQSwMPKfsNzXhPxL+9PSaaVQh5m5pXjNkWceLKgSQoIhOOgLQZNFU20yQbK0aaAAunD837nCXWLd4r3HqMGQUEAA+Bx42HdsYBRMCCJYg6lPPfFluKQ5f4blWIBLr3ccM7pHiYdRMJRw7TNhGoKlfa1PkBNw+ig5TWvi/n6px2lSeW0cyOueGZMfyXF1xQxBoKZvsnvWyx1yNgAd7TtsAfSHxxk16VbfJXEF9QZ1HtAEAOIgnhQbfVtaMNrqpCfTXn2Mw1XPUewBqTmYNKH9zyGe/8EcOWwDOisZ/OAYfMfWOrOkENgfx2/qGDbLswcqA+VnHpczVczNkI9Hc2A5L/uZt8fPp2dhZqeomkoIQwCiNUA35I2JA2BIgQTHMi+lChuH10FeQwGSIcBntBK6xxTikw5ciJo2pBvuyuFEv61ck+0WRmlCjsztqUMUKC2mJCMzcsNQ5kBCeCDANohBCSIw22QgCoYWhKBYNAjXwcE0M7XVJD2xx7Uh745goEOSEEzVZSMaTFpEtUAPZoBCVD5+l7//eNHzS9EVTWuDqagrQTaDegEFwVzpLZDwCOvhQoKQR0RzJUj/A4ZitMr4BSXglaVtKo+YwIqQLLULTEPlP/8Zu57+Sl618igP83WBZ8YbF5AOkbTCEhbMib0/6clvA5AWyuPbhpoJiFEp/vt0yQMkKAecOBTRWseV/HZ8nlXxgSUAyNLGVCZT6jcdkA/fcVyf5pWDXQdLjmJBJEO0ACJ6XjOBNj2VUSAHGAB38ZSbxsboQOOYDaAtBVK6HgBD2hoXSj9mqILnowlY4JMSxug4U3zb/o+3zlr1O8ZXObXm6JgiiA5AzaMfDuQAQhQAtBeHW3J5wGn3HW7cMutcOiQYCNYv045c5syuglIBWqdS2QAQ8C29TWIpsLtCUHrHl/xuAXP3Izfk7EA84HtEX8YSYGFnXMs/Giv/tdV/f6tttvgi2DyQCxh/afdgKAATHslAKLQBT95CP79323TAOMhF4Eq3PA9+MTHle0XKa96tdLbB1Q7KkAEIFSNBFNaEg73NQFfBVdS3KwnY8hYoKkU4JEMUKAEzP7GN/jODav8Lat63VbpalWBiQ1YQSwgtJkR1DlNTQYv3PIj+Ju/MLiysHEYuvJCFPhSBwtV5dtfhp0Pev7otcrKNUCl3QQBCKa2jbwE8EwphHlPOucYm/S3ZAzALFB6LD+O1oDZuSrL/vE2/bvX9bm/k6IpSF6II4+xBiIQETAdJgDQNvpdcPctyl9+yNBrhZGVQj4CS9uuLYZCJHQXYO9ewwff63nLO5WBAYF6MAA6oIMJTlAFdeCrnmRRG/Ce6rSrZrk3GOaDATWOEJajhwOiGw7gL1hpamt79EwTC5kkAqy0TDBtJgjBhAAfw/SE8KH3CFSE/oJggKgI+WVQHIJcD3gDSR2SKuRjGBuHvQeEc88XBA4fWAQI0kxh3tdaa71fUNyMJx13/PBB/vH3v6nfBw4Bk0D6WA3wQdH19+mBF29gpD+vm4ilBR0FIySY8D/wbUtdTviXf1Bu+SGsHRVO22644GWG7S+B854D2y6DMy6FrY12yznCik1CPYH5Sbjtdli9GjacaCAR0GBE+3xPQevgy+DnlaQBXx9L2fmw/+qlH9F/B8aCyo/nv8iE7wKmgeJrPq//9OkX+RUj1p2OQGxArEEQVDRrA3iAF6U2DwenhGf/nOU5rxBWH6dQ91DRML8VgJwIXcPK6Khw7uWGe+8SPvofnvv3eC7xbaUf+jhpglMXtKz4ed+ET8Yd4/v9bVmuwAwwHRj08RgA4ML8ie+bJv/LX9YP/uuz3FtWwEmEnNQLxhnIAzFIFFYAhVwMb31fjkKvwoKDgwqqR7gQEkiABQXxnLTR8LYPRFRnFSoelPZRh0TQGviKz8q+BT+Wwbt7sxwbuR4CxkPujiXC8siRAh7gJ/PIbWPcetGwbuw2uiosRYi2rcuASKsvQOQV5hVqAHKEq7jQp+2LrQKUlMgDTsCZMOqgGXwZtORJ55Q0gz+YcuAn/tZf+aK+//v72N827xcBnqgBAHVAMzVM0K/t5MeXjNDfJ7pJwqCKV8haFTSAiSdA0g7dZlaQtgkB3wImFciAM9UFquAXFZ1vwbspT3LI8dAe/7WXfEb/ujE4B9rg5wCeLAMAaoAHdLqG/NPt3H7msMyNWHeqSYlU2+ZoMAMIpnSs23T0tcOItCVNQZO2b/kSuAx+RpvzvXworX7vfv758uv1mulKE3oMmAilz5NtQDABF4wwH71X9yU1dhxf1JEur6s0vNJsnYAnvFtQ1wboASX0MwEp4AJ4PRNoVdEyLfAFj5vzJFOedMxxYK+/5S9/qB/6o2/qTcBUgA8jjx7T/y0O9AJDQQNFS+/fXcW5F22QF/YPmw12mcH2GkyXIEXB5oCcIDFgQUz75gZQwCsaDGvt2hVXDyNfVlypZcDspN/97d36yd/6Mj+sOBaAGWAqaAHQn9afzPQAy4ABoB/oW9NDz7svYts5o3Ll0ICcGvUYyUywXQbJC5IDCXuJTMYAgA/gaNjB1VutK/smfFryOjWtd/5on37lzd9mx/4SJQhXeDATRr30VPzNUD5UQ18woTcYE/3+NjY8a4vZtmFAt/X0sj5XNHmTFwhXkiZqr4Cwf0+BcAurXvG10gJ7ds/Iji886Hf85Q52A2kAXQjw86Ffeyr/aMoAxQAfRBfQDeQtmOccz4rto6w5YciMDnfp6q6YwXxET2zJAySOWi2lVE6YnizLgfun/N7v7mX/5x5g3IEPgItAOQAHte/vn/qIAvxKYBNwKnAmsB24DHgm8Bzg+cBzgRcAz8sU+s8Nrz0nvPey8Nkzw7E2hWP3AhH/G0cURn8IWANsBk4GTg8w5wDnBbh2nRdeOzO89+Tw2TXhWN3HAlw4diFA3KEotO37RwBtW14TIA1tu/RYJfnTis47B53nVsAHBTOOffwvrHvsx5swbgQAAAAASUVORK5CYII=\" title=\"emoji-unamused\"> ) I had plans on creating a <code class=\"language-text\">mongodb</code> backed blog, and for two years, you would find in the footer of my site <em>Blog Coming Soon</em>. <img class=\"emoji-icon\" alt=\"emoji-thumbsdown\" data-icon=\"emoji-thumbsdown\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAATlUlEQVR4Xu1beaymV1l/zjnv+q33fneZlelMW6hdgRJKKS02RjYjRozyjyEhwZigYmJM/MMQ4op/EIhxCYsgxASNFtCgrQiKCZSyWWXaaaG1Mx1mOnefb//effF3nnPovbkw3juGNumVb/K7513PfM/vWc9z7qUffX6EH+H/NcR+Hnrf2+5aJq+1XOXlkqR6rqKikydZmCazKp7E63GcX0wmg/Mfe2zc/0Hvf+Adb+iVorzNVf6rhBA3K0fd4Ch1wlGyWUsRKiEdwqeua6rKgso8pzROsiyeRbPxZH06nZ6ZJek3hVRfvP5Vd66EftNVdd0sVSXqos7zNI1FNR3++p/+8/iHRsC733zbqUan/RuNTvfOZrtzImw0lj3PF0JKfqmuSiqyjJJoRtF0SsPL/UvD/vCh/nD4lx/75urn/ujt954MvPBNYbPxk14Q3hGG4XHXd8l1HFJSkVKC5+GfPCEZ4bOUsiii2aBPo/4WEbhpzC9QMNcj13NJef6IpHLBVUMTVhRFledZnMXpII5mTxXx7IGNtWf+6r2fPbP+fybgt153w9GFI4e/snDk2Mm5hQVqdVrkez65rkPC/oOujLYKEJFnlCUJJUzEFu7Ql+cWl2/2m+2e53vk4D3HARSEdwQI0DNIgsg8ihpzUc2aL0DoFHNMNtaodfgILV5zPakwpBqkFRVsDyTVGpXgsSpKvgYroNl0BtIGtLmy2l9fXXvrB77w+L/tRYD8QRc73e7v9pYPn1w6fIiWlxapt7hA84cXqbvco+7hBeoewvkyoO8t9WhxcZGWjxym5aOH6CW33ko33f6Ke46dOokplnCvh/ct8P485uoCc3NtoEudTpPaILjTwthqUMMHUUVGR06epFO33Ead3hwsoE3hfIPCXhPvdqi71MN3mOfvMn9okRbm56i30AMWaAFz4//qLcw1P/2ue65f2osAZ/eF337DjUcanbm3zuuJ5rvUXpynsN0g6SqS0mgfA9XEP6AJ6K6EKY7G5EvCcx4JpUhA48LDsYvnlSSlHP0+II0NFQWJJKOyLPF+RQQtykKbdE6yzmmuN0+Bfg9uU4c+lUpwjLAmi3cwVHg3A4SgNFfkYIQPwX18IqG6jizvJKJ/vCoC/GbrtZ35bqfdaVOz1aIQWvFCF8IrYncVAsNO01F8licxuaoFU9dfOCDyrKCCGESaCJzX5oKoFAYJwiCYyKnEfSU4EpLUDpZlMO+MnMolNwVZjqIKZOMBJgIvYcQ5rpWOviypkhAIpCiQqSq4Ry3aV20BJNVrWjDHwPfJD4FAa1SSIyULvztw8ElRkScUyYYP4RtUu7X9osbT7Ws24AFFBRREqtbH7MclCEynE2BE48ubFI8G1Lg0T34DpPo+KU2sJqasOABDeLacojAxoYAlxUlKQ1ji5eGYZpMxbQxna1dNgOs5t3haeN/VwYuFl+IKwgPa/CSEkIFPBAKEMq5RWe3LZx+0b2clkBqz1wLlOQewZDik4dpFWj93lqIoQrw5TH6nC/frkucHpFyP3cqmS6DSVsIukycR5oA71RMSMkJWimmjP7nwN4+sP3K1BEjPdU8ox2GTZ3+VrLQr5ks2WRfa8Vybzurd0dUKbzWfJhw3WHwd9UFGOurT4NIFunzpIh2/9WV07MaXUtjtEul5K5AkKvM+m3xtwCTYEdovYQlZntGxaURHV1Zo+cmzvdbSuZ99/wOPfIyZ3icBDlJdTykrvAL2qpVqQNZW+Csk2kqYL50kLFAtrOlb7c36l2m4sUonb7+Djt3yUnadzJV4rqTKqe209bYbAbLmI0N4Lnk+nLOVBO0OMs5y69hw9OF3v/GGL//B5554Yr8EKCGEx9HaBjwJ7MyZ1RWJ2ON6mrGmuNortP9q7YMAmHs8HpEXNKn3omsoi2KS7SYE12ECz1fbU4hdvNr4QtJz+CE5KUmqkuOFghuHYSALIX+eiP5w3y4gpHKt0DbS4iEprCw/WNHVFSqqbb8vSBS5IU+bNISvC11EwYfhEmkcceyocE3qFJoXLJSL47reNb+wwzashVWcZZSSNmgTKWN4p64mBggFBrbTXbWL+d0kWC38b3VmWXPQw0zG92EFpIWHv5YQvsgwFjlQUBpNjZFLhxwQJVyXU6WQlgQ7H0k7udUELIsJ5ciCsU5jKmZTk1nizL0qAmpRsdoNdku3+3Q7xVF9Je1nRnAbrKBmjtxlzjBaB+ejwRZdfvosNbpzVFYV+3bFgpU4L0ngWqGfx1hzyOEfJiaWBWeFMi8pShKaTqZ0eTSlrdGMBtN4xRYr5d4EMJu1rTMEk8Dg4+8jYjunS6mpA2gHafoeTiCkIGv6NYTJCxas0gRkKc4zfjRNUzrz0IO0dPQok+CHIac+Yl2UfFwLAXD0Z1JwQim0XMQxVTjPMecsSmgcZyz8xY1xem6Q/svVEYAEjUJD2UJDMwHs0rDYgTg1BAS+eUjsCAyJ1T4ZLZEWns3fpL8c2srg/zFqgEa7TTfecy8tIhCiGjWxQEijAPthzVjUpg7nRRGItctozAmLm42nNNzcorPfveieeGb19246MvfLH/nq+e/si4AK1MLMXPYrgDQc11rCDpuvjZB1lnOmqKUi8jGdsBYDcxSlCXwwX05/qPu5vK3y7FnhZ6MR5Zj7ZW98M3UOH6ZaW41OgUoZKxTbZiV2kCAAKmueGwEW5w5Jx6NKpeRDrACKO1xUMsvLe5I0/ygR3b0vAkpEJGgtYLYroKzsDUCQIcQyIHCcw5+V65LSBY5qEIffUhMAQc3ihctVsGnLWBMACx2gEKgmWPMvnbqeOotLVKQgs9WgyoPwLO224Rk7kjb+7TBC/UDhkUpArMjJ5bggKID1+q0IltUhP9i6c9+lcF4UGSIya8tEVViCXozYwEQsDCvG5nSwLyVJYQIeyQAEFEBp+apMgILgVDEJ7AJcwuoUiHfQdDE6VpIIwiMMmYLp++Ir5trlhUoIXijVeuWZ56aCxbnC6OCa4wOOo/ZNQJblY6SmBY7A2nTz3JSgSrFQbBmWZdLCZAkIUFTq8lkLnSTWR3HbrtZqgKO5jtY2ABYZp0AOiDmOq9q4ichKUoFj6v0r5B4u0sx1tgBZVqa40nEDJAv9rkbFLmziD6gFsr0JSLMNBJJTiNbaHWzwsX5sDN/kXXaLXPsy+54qXaq1Jdh7JLSfCuMGTAIBIMzOQzwKrjfGCFg1yAA95EyJVO6TcB0TBIXAaKQWZEivrTtRweSamqI2MasogATkxjPuLiXTCSVRrLl090NAPY2SSwkmyLlIybnlpZSywpscjOzAkbcG63ka6z4dzC0gqXBdqe2GRV0xERVgj5kMzuWC3YbT3dqF87R29kk6dPI6woxmuTuFZcQJJeMhpdMp9xsKmzZzCGnLaqDkeTAnZ5g0SSmF8qZZQTEwGEeoCaL7bc1GexIwS7OnosmE4tlMWwPnVhDApSrYBkqTyvSY5pRMZty4VEHIz5AQNlCxV7OmTfyypTUGs9jCnBgd14cACf3nFz5Px1/8Elo6cY2uD7gpmiBICszjNtok4WKu6yGwtQndGt152o49Spp0m2ZcVo/GE8ouXKTzF5+mx1ZGn7j/ic337TcGVBuD6OHJaEzj4YCauhvkufwlSqWjO2vP1vApzCyiCBqqSJAbNokEBMIxmWraRHJr5hbcGiulJIV5Pc+jIvDhai2KphE9+egj9Og3vkY3vuzldO3LX0HNhSXyGk1yPZDrgDybGiqOLfpYjzUHWKOYkqvFEMoLuj3yOvOUO98+9g+PbmZXKoTU7vMkzrJr5oNf8B3Vch3uA5qJU+78cuqKwHCE/D3u9xlIc+wGrBGlTPoSZLRPgo+FJY80mWX9bECtbLCCJrlKPHXTzXT7T/0MNXpL5DZb3GSpXMkolaDKgbY56ksiV4+gXAG11WAtqahrzi5RlFKWRNc1ZPWlx9bG39a397KA8vwkG64OJvc1w61fg+yUQdPtTocC3+MHkCU5yCRgOZ5OmIxWN8FM0GZVs5BBo41TxYTAeli4gstlBTi454JUEAZTd12XSpCHuMJdqKOnrgMxxFoVXggB8S5nJJsPbU+S6u3lsHIl3ndNyqacLaUSii1Tc73UCa4honw/LlAC+eefuPzx0HPugP/fEU1nZHqEHkdj7rwkKelAGccxzcByvdEfvbikblaZ8r8NIsJmi/cRpCO1DRgfBjkFl48uSe0CmLMuG2wJeZmT67haWJ5f4J6MEw7eJQvKXWGGLUZtY4QMQWnKLbI0K3h9kEYxxdGUvye+8747QjWQbkX58DOPrP3mT1zfe8fSJHpdO/APea5ypCQ23wzVUpRmg0Gc/felUfrQuc34az+dVG+5vax+saxqdpkKY7PTIo+gbU5nFYGRZxssHsigEqgxFLAaEJsEEU3QHWotjUmkISldGUYe53dybEoEMLLwhc4WJQc/01sscsrilCbjMQ22NvVuFY6n1I/iR/dJACMFZoO46H/60Y0PdX3nr0/OeS9qBt5c4FAjLep0lOSXLw3T1UFaTq1f0Ye+/PSH3lmL8Laq+jlezrLWgFaTzVxKbnablMpFkyIJjTt+QG5ecE8ghOtsoS/oIKA2EACJ9xhcE1SVxKitid3KxBlGwVZZ5AULn0Dr48GANtc2aH11XS+LH7z/v9bPbDe09iYgB6b2Ho3Soji9XoyJIrndC2GUQMGjneuDD55737sktWoSr4emONUpQDSFbjaaDZOi4lFKkOC63PjwG2ZTNM1guqMJPf7wf2DX5yg1ez0STqAFBxS7kd2XYFSVeS/POStxXJohhQ8xR78/qNZGswfu+9bKeyKict8WYDGzYwE0AA9QOwio7L1sR3DxgdYnHjr3+7/kqDY0/WreD/RMbS50inRMnxxXuGBSnscTqroi5YekVMCt+OE0GfzdP331d+bbjd51x5dumWuFNznSOSKVbEhBrpRC2M3UOsvLssw1CUk8TbLhNE4vrg2Tbz66Pv7KU5vxeavMHKj2T8A2CamdwL0CAfkOCwiBYoKrf/vwxfe83XM/6Pve9a4PoZTD6VEKbc62oyvNfkOtXBBR8opSwCVqvia7j69Nn1w9O5zSt1b+lYhkr+mEncALWr4bONp82ALKKk5QuAuqJtM86qdFvMM6c2BmEe+9O7w3xD56wC1gHpi74/j8rW959amPXHvqVPPQ8WM0v9CjBjKDo62Bl8k17ypXtpZPZxENtzZo5cIzdOHiKn396c33fubM5n12XmUhLGhXa7K2qHa4ZmKVNwZme7vA3qj38czUEiW/8czgsRvOtz7RCpu/GjQaHAh5w0UEJJXktYKQkslQymHtCwUIU7LPhe5tOrZawRzGbhKuLHxqCYiBbM+m6A8ZU0Bp3H9m9ZPHF9pvajbDa4PAN2U1/oWBz1mBKhAgTW5XUnJFR8pEfFeK41Z7KSDtnHIPAnaQANjP801ADUwApx8X7umLW3+OYPb+RhNW4PtsCXADJgMskLIlc223vqQgJsdzZfMVcKaHB5TQc/iRz9G8JZMAPPDYxhcurPW/2L88oOlwSHGU6KYLXMAk8qqy7W+zWcKqdc1udLk6MBnmhUgA7cggsy+d3fzjrX5/OhqMKJqNeTc41bkbQpcY6yylIom4vaaI2EpC1z1+z80LN7+ACWBEwPSRlclTT1wafnQymfDWdZqmtlFqzL9kVQiuAVzfI9/zKAzdVrvlv/OFTkBB1gr+/vTFT24ORqfjJOW2mKjJVINhg9f8jXaXmt0etbrz1Gy3qOH71HCd17/ttkPNFzABjBiYRDmNHr80/Hie6S5TQZWUnPq8ICC/1aFwDsIvLVJ7aYnaKIGbCJqh5x7FI7e80AmobSEylcKZZXluG6OC052EhMoFoHGv2ebfCewsgIT5eWo1AiEk6oHn8OPQ8/PJgFnoSYnq1UR+ZkaYwkcJTn2KTJM07M6BAF05bpKnxjccAAIYiSNLYZvrtL1exsCngpRd8Tm+S34TcaHV1DXDsRe2C2yjVLUUZh1/BU8xfJAUilzPIy/wSTlqjojUQSCgFrJmwm1Xb4cV2HNmwLqF7SC7Snmak4PgAlRXomIhJYBRADUfMRE7F+zmngCsog6CBYhK1Lnp6e/yA2nl48uC+/5laX6ZoqhrXmEeBAJISFFyFrA9bh6tdLw/oAWvza/OZFnGFWNelCsHhoAir2JugDAJxgIw2J1gs79XcFvb7DskcUSTKDnDbB2EIJgW6Jhlac2/7JQXTATZ5ibAFWIap/wHGJPRiEajWXxua/rwQSGABtN0axZDvxG0m8S8AZLGsdE4rs3GYxoP+jTAdvkAPf2N4fTBr5wfX9AcHQgLeHxltDaZTsfjwZD/smM8HAIjmgwnNMZ5f3ODtlbXaBPY2OwX314Z/cXOxutzAUHP72fhV+4++dkTR5buWj60zH/dEaLak0Lwvv4EhGxubtL6+iZ9Z2X4J586vfpnRLQBjA5EHQCUl8fxv4fe4K4iL+DrEwqCgOugOLa/4DiclE+vTz78qTNrH7cryRSgA0PAg2f7n7pX0ivjJLujPxp1XMfl+jjJi9Fwlp1+YmN231e/O/j6jp5+SgfoEwAngJcDdwM/Dtxrx9cCrwFeCfwYcAjwADpIFpABkSVCAO7urXl7f2z9PqMD+AmAZeAk8GLgJXa8FjgO9K6g+QORBXZanrdrmVsBuUX9fBHwP6w5oUlUPapLAAAAAElFTkSuQmCC\" title=\"emoji-thumbsdown\"></p>\n<blockquote>\n<p>“The road to Hell is paved with good intentions.” - Disputed Authorship</p>\n</blockquote>\n<h2 id=\"Gatsby-to-the-Rescue--My-New-Site\"><a href=\"#Gatsby-to-the-Rescue--My-New-Site\" aria-label=\"Gatsby to the Rescue  My New Site permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gatsby to the Rescue! – My New Site</h2>\n<p>Once taking a full-time position, especially when you have a family full of children, time is of premium value. I just never had a need or desire to update my portfolio online. I figured if recruiters wanted to head-hunt me from my current job, they need to come with a good monetary offer, good benefits and companies will have to go off content I have produced. <strong>So Why Update My Site Now?</strong> <em>Am I looking for new work?</em> Yes, and No. </p>\n<p>I’m not actively seeking new employment, but I am looking for solutions for upcoming projects at work, but more importantly, I’m looking to give my side-business a boost by offering niche services. There is a market for helping small businesses get a site up and running on <code class=\"language-text\">Wordpress</code>, <code class=\"language-text\">Squarespace</code>, even <code class=\"language-text\">Wix</code>, but **I want to produce sites I like to build as well as sites optimized for the web of the future - speedy, SEO optimized, accessible, and PWA friendly. </p>\n<p>I started seeing devs I know tweeting about <code class=\"language-text\">Gatsby</code> so I checked it out and fell immediately in love. I have downloaded and configured a dozen or so starters, and I have started making open-source contributions to the <a href=\"https://github.com/gatsbyjs/gatsby\">Gatsby repo on Github</a>, but it is time to put something into prod, and refactoring my portfolio and adding a blog seemed like the perfect first candidate. <a href=\"https://twitter.com/WesleyLHandy\">Hit me up on twitter with feedback on the new site</a></p>\n<h2 id=\"My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\"><a href=\"#My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\" aria-label=\"My Plan For This Blog  Or Why You Should Come Back permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>My Plan For This Blog – Or Why You Should Come Back</h2>\n<p>After this introductory post, I plan to post on the following:</p>\n<ul>\n<li>Technical Post on How I Built This Site</li>\n<li>Series of Technical Posts on Coding Practices I&#x26;rsquove Learned During My First Two Years of Professional Development</li>\n<li>Series of Posts Giving Specific Details and Advice Concerning Transitioning Careers, or On Becoming a 2nd Career Dev</li>\n<li>Other Technical Posts as topics arise</li>\n</ul>","id":"698dced9-6847-5220-ab59-f3e554d5a4ff","timeToRead":2,"frontmatter":{"date":"2019-04-04","path":"/blog/hello-world.html","tags":["gatsby","intro","development"],"title":"My New Blog - What To Expect from Me?","featuredAlt":"Batman says code like a champion today","redirect_from":null}}],"netlify":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"forestryio":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"tinacms":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"onegraph":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"stackbit":[{"excerpt":"This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for Javascript APIs Markup.  It's an approach to developing…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHnphaol//EABsQAAIBBQAAAAAAAAAAAAAAAAECMQADISJC/9oACAEBAAEFAm1HLHM2zRn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8BMX//xAAZEAADAAMAAAAAAAAAAAAAAAAAESEQE1H/2gAIAQEABj8Cg9l4Uef/xAAaEAADAQEBAQAAAAAAAAAAAAAAASERQTGR/9oACAEBAAE/IUSXDa4OSQM06wTej2CZ8Lo//9oADAMBAAIAAwAAABAED//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxA1f//EABcRAQEBAQAAAAAAAAAAAAAAAAERANH/2gAIAQIBAT8QmDmWt3//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFR0f/aAAgBAQABPxA3UFfqIq4iBVXzipznYvsELYAPGbAtXVpodL2z/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        title=\"San Francisco JAM Stack Conference: Javascript APIs Markup.\"\n        src=\"/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg\"\n        srcset=\"/static/303da88efebc2e830b4383b0143d311b/afcd2/jam-stack.jpg 300w,\n/static/303da88efebc2e830b4383b0143d311b/82472/jam-stack.jpg 600w,\n/static/303da88efebc2e830b4383b0143d311b/c35de/jam-stack.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This past week, I had the joy of attending the JAMStackConf in San Francisco with 550 other excited and curious developers. For those not familiar, yet, with the JAMStack, it stands for <strong>J</strong>avascript <strong>A</strong>PIs <strong>M</strong>arkup. </p>\n<p>It's an approach to developing applications that result in highly performant static sites that consume APIs for dynamic content. </p>\n<p>Lest you be dissuaded by the term <em>static</em>, this refers to what the browser receives not to how interactive a web application can be. In fact, Static Site Generators (SSG), like Gatsby, could be considered replacements for framework boilerplates like <code class=\"language-text\">create-react-app</code>. Not to start an argument there, there are plenty of resources online to familiarize yourself with the JAMStack, if you are so inclined. </p>\n<p>For now, I want to offer a few reflections on my experience at the conference and the state of the JAMStack that I gathered from participating.</p>\n<p><a href=\"https://jamstackconf.com/sf/schedule/\">Watch JAMStackConf Videos</a></p>\n<h2 id=\"The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\"><a href=\"#The-Future-of-the-JAMStack-is-Dependent-on-Solutions-That-Are-Being-Developed-and-Those-That-Are-Launching\" aria-label=\"The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Future of the JAMStack is Dependent on Solutions That Are Being Developed and Those That Are Launching</h2>\n<p>Some of the biggest hurdles for developers interested in developing on the JAMStack involve OAuth, Live Edits, Live Preview, CMS Solutions that are non-developer friendly and trusted, and handling builds of Large Sites, handling builds with a large volume of content production 24 hours of the day. Several of these questions received answers this week:</p>\n<ul>\n<li><a href=\"https://twitter.com/sgrove\">Sean Grove</a> of <a href=\"https://www.onegraph.com/\">OneGraph</a> demoed an amazing <code class=\"language-text\">graphql</code> product that seamlessly integrates OAuth with several popular services. </li>\n<li><a href=\"https://twitter.com/scottgallant\">Scott Gallant</a> of <a href=\"https://t.co/8nthzRUvwl?amp=1\">Forestry.io</a> announced the launch of <code class=\"language-text\">TinaCMS</code> with its widget for live-editing React-based sites.</li>\n<li><a href=\"https://twitter.com/ohadpr\">Ohad Eder-Pressman</a> of <a href=\"https://www.stackbit.com/\">Stackbit</a> revealed their awesome tool for quickly combining Themes, SSG, and CMS for quick builds or just testing out new tools.</li>\n</ul>\n<p> These are just a few of the tools we heard about and were able to talk about later with vendors.</p>\n<h2 id=\"There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\"><a href=\"#There-is-a-Growing-History-of-High-Volume-Campaigns-for-Major-Firms-Being-Run-On-the-JAMStack\" aria-label=\"There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>There is a Growing History of High Volume Campaigns for Major Firms Being Run On the JAMStack</h2>\n<p>Besides showcases <a href=\"https://www.gatsbyjs.org/showcase/\">like those on Gatsby's site</a>, it's great to hear from major corporations and major agencies finding the JAMStack to be a solution for many of the problems they have faced with quick turnarounds, organizing development workflows and teams, and providing high-quality performance at scale.</p>\n<p><a href=\"https://twitter.com/justinbwatts\">Justin Watts</a> from Loblaw Digital shared with us how they were able to redirect a corporate culture towards greater efficiency while producing major sites used by millions of Canadians.</p>\n<p>Two of the more broadly well-known viral social movements of the past two years—<strong>The Kaepernick Nike Campaign</strong> and <strong>The Chicken Sandwich Wars of 2019</strong>—had behind them JAMStack solutions that were able to handle hundreds of thousands of users at a time. </p>\n<p>At the <a href=\"https://www.rbi.com/\">Restaurant Brands International</a> booth I heard it said (in so many words):</p>\n<blockquote>\n<p>The chicken may have run out, but the website surely didn't</p>\n</blockquote>\n<h2 id=\"Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\"><a href=\"#Netlify-Function-Serverless-Functions-etc-are-a-necessary-tool-to-master-to-take-full-advantage-of-the-JAMStack\" aria-label=\"Netlify Function Serverless Functions etc are a necessary tool to master to take full advantage of the JAMStack permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Netlify Function, Serverless Functions, etc., are a necessary tool to master to take full advantage of the JAMStack.</h2>\n<p>I was fortunate to be able to attend the <strong>Serverless Workshop</strong> led by <a href=\"https://twitter.com/DavidWells\">David Wells</a>. Check out his stuff wherever you can find it (<a href=\"https://github.com/davidwells\">like here on Github</a>). </p>\n<p>The key to creating dynamic JAMStack applications is mastering the middle-letter of the JAM—APIs. I feel very empowered by what I learned from David. His workshop was deep where needed and broad where needed. I left with a million use-cases buzzing around my brain.</p>\n<h2 id=\"Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\"><a href=\"#Is-there-a-traffic-JAM-ahead-While-it-seems-there-is-a-growing-number-of-devs-who-love-the-JAMStack-I-talked-to-very-few-who-had-the-opportunity-to-work-on-it-day-to-day-in-their-current-position-or-who-thought-its-unlikely-they-ever-could-at-their-current-job\" aria-label=\"Is there a traffic JAM ahead While it seems there is a growing number of devs who love the JAMStack I talked to very few who had the opportunity to work on it day to day in their current position or who thought its unlikely they ever could at their current job permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Is there a traffic JAM ahead? While it seems there is a growing number of devs who love the JAMStack, I talked to very few who had the opportunity to work on it day-to-day in their current position or who thought it's unlikely they ever could at their current job.</h2>\n<p>If this paragraph is all you read, this is the most important takeaway I had from the conference. I am confident in the direction of the JAMStack, the progression of the development and release of dev tooling, the quality and ease of use of the development, build and deployment process, but, but, but, and perhaps this is always the case with new tech (legacy code), I along with many other developers have little chance to use the stack without changing jobs, going freelance, or building stuff on the side.</p>\n<p><strong><em>Could this create a ceiling for the JAMStack?</em></strong></p>\n<p>I, for one, intend on using it in all my side-work. But, honestly, I have a wife and three kids. I can't be coding 10-12 hours a day. I need my coding passions to line up with my employment or <em>fughetaboudit</em>!</p>\n<h2 id=\"That-is-some-sweet-tasting-JAM\"><a href=\"#That-is-some-sweet-tasting-JAM\" aria-label=\"That is some sweet tasting JAM permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>That is some sweet tasting JAM</h2>\n<p>I said the previous paragraph was the most important, it is, for the sakes of my thoughts on the stack, but this is my favorite. I really enjoyed getting to know other developers at this conference.</p>\n<ul>\n<li><a href=\"https://twitter.com/bauhouse\">Stephen Bau</a> is a full-stack developer and UX design mentor in the Vancouver, BC, area. He is super friendly and it was a joy meeting him.</li>\n<li><a href=\"https://github.com/ozlop\">Ozzy Lopez</a> is a self-taught developer with Snap-On Diagnostics. He is a very knowledgeable developer and was a great person to spend time chatting over how to use the tools we were learning about. </li>\n<li><a href=\"https://twitter.com/MonicaNorris1\">Monica Norris</a> is a Front End Developer in the Chicago area. She really impressed me as a person. She continually connected with new people and then connected them with each other. I met at least four people just because of her. She would be an asset to any team and I think would be a great team leader. Honestly, is there a ceiling for her? No ceiling at all.</li>\n<li><a href=\"https://twitter.com/DJFalcon23\">Derek Fields</a> is a developer from Baltimore who knows his stuff, he's a great listener, but when he speaks, you need to listen. You can tell he has put a lot of thought in what he says.</li>\n<li><a href=\"https://www.linkedin.com/in/amitrathik/\">Amit Rathi</a> we all heard from the podium. He is a Freelance Developer who is very knowledgable about Wordpress. I want to mention him because he took time out of his lunch to chat with me about some Wordpress issues I was encountering at work with the <code class=\"language-text\">wp-json</code> REST api.</li>\n</ul>\n<p>Finally, I want to share a story with you about <a href=\"https://twitter.com/sgrove\">Sean Grove</a> from OneGraph. </p>\n<h3 id=\"Servant-Leadership-Exemplified\"><a href=\"#Servant-Leadership-Exemplified\" aria-label=\"Servant Leadership Exemplified permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Servant Leadership Exemplified</h3>\n<p>When I sat next to Sean over lunch, I had no idea who he was at the time. We were all wowed by his presentation not one hour later. Over lunch, he was very cordial, friendly, and engaging with everyone around the table. He didn't talk about himself, but asked us questions about who we were and what we did. So humble. That day we were served Cornish hens (with plastic forks....) and behold, my fork busted in half. Before I could do anything, without a word, Sean went and grabbed me new silverware. Then he chatted with me a bit as lunch was ending. </p>\n<p><strong><em>Why do I share this with you?</em></strong></p>\n<p>We not only need great technology to change the world, we need great people. Here is a founder of a new startup, being humble and through that showing great strength. I think we need more people like Sean and should ourselves try to emulate that type of servant leadership. Match it with some serious public speaking chops and you have someone people will follow.</p>\n<p><strong>This is also a proxy for what coding is all about.</strong></p>\n<p>Anthropologists have long recognized that technology is simply an extension of humankind. The JAMStack, or whatever stack, company, job, or whatever, <em>tech is always about people</em>. What we produce is intended to help others in some way, shape, form, or fashion. </p>\n<p>I've been encouraged this past week to remember people when I code. People I love, people I work with, people I meet, and really all people. We never know how far some piece of code we craft will go, nor how many others it will touch. </p>\n<p>That's humbling and yet exciting to think about, isn't it?</p>","id":"3991f641-dc67-5fd4-b8ec-27c0dc40db55","timeToRead":7,"frontmatter":{"date":"2019-10-21","path":"/blog/new-tools-new-friends-reflecing-on-jamstackconf_sf-2019.html","tags":["JAMStack","gatsby","netlify","forestryio","tinacms","onegraph","stackbit"],"title":"New Tools, New Friends: Reflecting on JAMStackConf_SF 2019","featuredAlt":"San Francisco JAM Stack Conference: Javascript APIs Markup.","redirect_from":null}}],"wordpress":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"security":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"apache":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"htaccess":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"viruses":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"linux":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"permissions":[{"excerpt":"You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email... ... on page x some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.583333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHixmKg/8QAFxABAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAQABBQJ27rK2ut//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAEDFB/9oACAEBAAY/AjVSr//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExQf/aAAgBAQABPyHCzkLAteE6hqBBCpqLZ//aAAwDAQACAAMAAAAQkA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Q1H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAIWFBof/aAAgBAQABPxDlRKQnkycI4CfmuLxnd44AZm0Xv1zNrv/Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        title=\"Someone holding a laptop with &#39;You&#39;ve been hacked!&#39; displayed upon the screen\"\n        src=\"/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg\"\n        srcset=\"/static/66c5a6070912c2b67175cdce5e6880a3/afcd2/hacked.jpg 300w,\n/static/66c5a6070912c2b67175cdce5e6880a3/82472/hacked.jpg 600w,\n/static/66c5a6070912c2b67175cdce5e6880a3/c35de/hacked.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You've been working on a project for months, you've handed the keys over to the client, and then you get that dreaded email...</p>\n<blockquote>\n<p>... on page [x] some users have been experiencing weird advertisements and popups. I think the site has been hacked! I don't know what to do. Please help! ...</p>\n</blockquote>\n<p>I faced this situation recently. I volunteered to finish up a project for a nonprofit organization (not the one where I work 9 -5). They were one year into a new site build when the developer they originally hired ghosted them. </p>\n<p>I'm a JavaScript guy, so I wasn't all that familiar with the entirety of the <code class=\"language-text\">Wordpress</code> ecosystem, but I figured I knew enough, I had been building my own plugin for work to inject a <code class=\"language-text\">React</code> application via a shortcode, thinking, \"How hard can it be? It's not even real development...\" (don't get offended, just expressing what I was thinking at the time). </p>\n<p>I was very aware of security issues in a <code class=\"language-text\">Node.js</code> environment, but <strong><em>I had always relied on other services to take care of hosting security</em></strong>. I had heard of <code class=\"language-text\">.htaccess</code> files,  but I'd never put my own LAMP stack application into production from scratch. I hadn't even given it any thought since I have been focusing more and on tech like <code class=\"language-text\">React</code>, <code class=\"language-text\">Gatsby</code>, <code class=\"language-text\">React Native</code>, and even a little <code class=\"language-text\">Angular</code>. </p>\n<p>As easy (in terms of difficulty) it was to handle all the front-end requests of getting the site finished to the client's expectation, <strong><em>I took for granted my own ignorance of the rest of what was involved.</em></strong> I want to share what I have learned over the past two weeks so that (1) I won't forget next time, and (2) so you can avoid many of the mistakes I made. </p>\n<p>I am going to try and provide links to all the sources that have helped my in my recent journeys and to briefly talk through some of the more important parts. Let's call this:</p>\n<h2 id=\"Wordpress-Security-101\"><a href=\"#Wordpress-Security-101\" aria-label=\"Wordpress Security 101 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wordpress Security 101</h2>\n<ol>\n<li>\n<p><strong>Always Hire a Developer You Either Know or Can Verifiably Trust</strong></p>\n<p>It is very tempting to hire the cheapest developer you can find. But sometimes you get what you pay for. </p>\n<p>I like that there are sites where developers can be rated, or public reviews left, like Upwork or LinkedIn (want to suggest others?). These help provide accountability for the developer and some sense of security for the client. In this particular case, the original developer took a low fee for a quite complex site and cut a bunch of corners. </p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.upwork.com/\">https://www.upwork.com/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Never download and use unlocked or <code class=\"language-text\">nulled</code> themes - pay the regular fee from a reputable theme marketplace. Otherwise, you may install Malware!!!</strong></p>\n<p>I didn't even question the use of the theme on the client's site. Knowing the client, I assumed they would have purchased the theme themselves but it turns out they left it to the developer, who perhaps out of ignorance or a willingness to cut corners downloaded a theme online that was corrupted with the <code class=\"language-text\">wp_vcd</code> malware.</p>\n<p>I only discovered how long the malware had been there by comparing the current site with versions of the codebase that existed while the site was offline or in maintenance mode.</p>\n<p>This particular Malware was found within <code class=\"language-text\">functions.php</code>, and it created three files within <code class=\"language-text\">wp-includes</code>: <code class=\"language-text\">wp-feed.php</code>, <code class=\"language-text\">wp-vcd.php</code>, <code class=\"language-text\">wp-tmp.php</code>. It wrapped pages with malvertising scripts and also added a script that logged user's IP addresses who had permissions to edit the site and systematically ignored those users, so they would never detect the malicious behavior when browsing the site themselves, whether logged in or not, whether browsing privately or not. </p>\n<p>After logging into the remote server as an administrator-level user, I found the odd looking files at first within the <code class=\"language-text\">wp-includes</code> folder. I removed them, thinking I had solved the problem. The Malware was creating redirects to sites with the <code class=\"language-text\">oclaserver</code> domain and logging IP addresses to <code class=\"language-text\">wp-feed.php</code>. I used the following command-line script to find these files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">grep</span> -Ril <span class=\"token string\">\"oclaserver\"</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">grep</code> searches files for lines matching a given pattern.</li>\n<li><code class=\"language-text\">R</code> makes the search recursive, looking through all files and directories within the current director</li>\n<li><code class=\"language-text\">i</code> ignores case</li>\n<li><code class=\"language-text\">l</code> suppresses the output to only list the filename</li>\n</ul>\n<p>Initially, I though this solved the problem, but the next time I checked, the files where back. I deleted the files, then checked again, immediately, the files were once again there, full of the same content. This means either my <code class=\"language-text\">wpdb</code> was corrupted, or some other file that gets called repeatedly by Wordpress was corrupted, or possibly both.</p>\n<p><strong><em>What did I do next?</em></strong></p>\n<p>Before scouring through my DB in <code class=\"language-text\">phpMyAdmin</code>, I first identified and deleted all unused themes and plugins. The files kept appearing. So I started searching for terms within the files. </p>\n<p>What found me the culprit was that within <code class=\"language-text\">wp-temp</code> the code was setting a password variable. My only thought is that this was a hash of the admin password (so I made a note to change the admin password after cleaning up). I ran the same <code class=\"language-text\">grep</code> command but searched instead for that password value. </p>\n<p>Lo and behold, the <code class=\"language-text\">functions.php</code> of the parent theme lit up. There, I found a bunch of hacky code that was wrapping all the pages with the malicious script and systematically ignoring the IPs where an admin user had been logged in.</p>\n<p>After deleting the code, I deleted the malicious files from within <code class=\"language-text\">wp-includes</code> and the files didn't return. I wasn't yet certain the Malware was completely gone because I noticed that the code in <code class=\"language-text\">wp-temp</code> was creating a cookie on the client.</p>\n<p>Before changing the admin password, I reset the <code class=\"language-text\">SALT Keys</code> within the <code class=\"language-text\">wp-config.php</code> file using <a href=\"https://api.wordpress.org/secret-key/1.1/salt/\">https://api.wordpress.org/secret-key/1.1/salt/</a>.</p>\n<p>Then, I cleared the cache and cookies from my browser, and logged into the <code class=\"language-text\">wp-admin</code> of the site from an incognito window. <strong>Only then did I reset the admin password.</strong> </p>\n<p>Finally, I created a new admin user for myself and encouraged the client to add 2FA for their login via the <a href=\"https://wordpress.org/plugins/miniorange-2-factor-authentication/\">Google Authenticator Plugin</a>.</p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/\">https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/</a></li>\n<li><a href=\"https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting\">https://stackoverflow.com/questions/46219263/php-code-in-functions-php-of-all-wordpress-websites-on-my-shared-hosting</a></li>\n<li><a href=\"https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/\">https://labs.sucuri.net/wp-vcd-malware-comes-with-nulled-themes/</a></li>\n<li><a href=\"https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html\">https://blog.sucuri.net/2016/05/nulled-wordpress-themes-malvertising-black-hat-seo.html</a></li>\n</ul>\n</li>\n<li>\n<p><strong>On your server, add a new user and remove root login to make it harder for someone to hack your server.</strong></p>\n<p>Since the client already had their site installed and running on Ubuntu 18.04 a Digital Ocean droplet, the previous developer had <code class=\"language-text\">ssh</code> access to the droplet. I really didn't want them to be able to log back in, whether or not they had nefarious intent. I noticed there was only one root user on the system, so I created a new user for myself:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> adduser myuniqueusername</code></pre></div>\n<p>I then added my new user to the <code class=\"language-text\">sudo</code> user group:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG <span class=\"token function\">sudo</span> myuniqueusername</code></pre></div>\n<p>And then I added administrative privileges to <code class=\"language-text\">myuniqueusername</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> visudo</code></pre></div>\n<p>Within <code class=\"language-text\">/etc/sudoers</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">myuniqueusername ALL=(ALL:ALL) ALL</code></pre></div>\n<p>Finally, within <code class=\"language-text\">/etc/ssh/sshd_config</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">PermitRootLogin no</code></pre></div>\n<p>Then from command-line, restart <code class=\"language-text\">ssh</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> <span class=\"token function\">ssh</span> restart</code></pre></div>\n<p>From there, do whatever is necessary to <a href=\"https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/\">create <code class=\"language-text\">ssh</code> keys for your new account</a>, set those up, logout, and then <code class=\"language-text\">ssh</code> back in as you.</p>\n</li>\n<li>\n<p><strong>Harden file permissions on the server to prevent unwarranted changes. From within the root directory of your Wordpress installation (perhaps <code class=\"language-text\">/var/www/html/</code>) do the following</strong>:</p>\n<p>Find what groups your user and your server belongs to and make sure that your user has ownership of all your Wordpress files.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">groups</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">usermod</span> -aG groupname myuniqueusername\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -exec <span class=\"token function\">chown</span> myuniqueusername:groupname <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +</code></pre></div>\n<p>Change files to only be writable by owner (you), and only readable by others, Change directories to be only be created, modified, or deleted by you or Wordpress, and prevent anyone other than you or Wordpress from reading or writing to <code class=\"language-text\">wp-config</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type f -exec <span class=\"token function\">chmod</span> <span class=\"token number\">664</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">find</span> <span class=\"token builtin class-name\">.</span> -type d -exec <span class=\"token function\">chmod</span> <span class=\"token number\">775</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> +\n<span class=\"token function\">sudo</span> <span class=\"token function\">chmod</span> <span class=\"token number\">660</span> wp-config.php</code></pre></div>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/\">https://www.smashingmagazine.com/2014/05/proper-wordpress-filesystem-permissions-ownerships/</a></li>\n<li><a href=\"https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions\">https://wordpress.org/support/article/hardening-wordpress/#changing-file-permissions</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add hardening to your <code class=\"language-text\">httpd.conf</code> Apache configuration by disabling Server banners, hardening your <code class=\"language-text\">.htaccess</code> file, by disabling directory listing, disabling HTTP Trace, preventing MIME sniffing, preventing clickjacking, preventing some forms of cross-site scripting, and securing your cookies within <code class=\"language-text\">wp-config.php</code>.</strong></p>\n<p>Within <code class=\"language-text\">/etc/apache2/httpd.conf</code> or <code class=\"language-text\">/etc/apache2/apache2.conf</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ServerSignature Off\nServerTokens Prod</code></pre></div>\n<p>Then from command-line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">service</span> apache2 restart</code></pre></div>\n<p>Within <code class=\"language-text\">.htaccess</code>, insert between <code class=\"language-text\"># BEGIN Wordpress</code> and <code class=\"language-text\"># END Wordpress</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Options -Indexes\nRewriteEngine On \nRewriteCond %{REQUEST_METHOD} ^TRACE \nRewriteRule .* - [F]\nHeader set X-Content-Type-Options nosniff\nHeader always append X-Frame-Options SAMEORIGIN\nHeader set X-XSS-Protection &quot;1; mode=block&quot;</code></pre></div>\n<p>Within <code class=\"language-text\">wp-config.php</code>, add to the end:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_httponly'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.cookie_secure'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n@<span class=\"token function\">ini_set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'session.use_only_cookies'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean constant\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>There is some discussion over whether or not the above method is best, you could and perhaps should also add cookie hardening to your apache server configuration, see links below.</p>\n<p>Links: </p>\n<ul>\n<li><a href=\"https://docs.sucuri.net/warnings/hardening/\">https://docs.sucuri.net/warnings/hardening/</a></li>\n<li><a href=\"https://geekflare.com/wordpress-x-frame-options-httponly-cookie/\">https://geekflare.com/wordpress-x-frame-options-httponly-cookie/</a></li>\n<li><a href=\"https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag\">https://wordpress.stackexchange.com/questions/175436/cookie-set-without-httponly-flag</a></li>\n<li><a href=\"https://geekflare.com/http-header-implementation/\">https://geekflare.com/http-header-implementation/</a></li>\n</ul>\n</li>\n<li>\n<p><strong>Add Security Plugins like <code class=\"language-text\">Sucuri Sanner</code> and <code class=\"language-text\">Limit Login Attempts</code>.</strong></p>\n<p>Links:</p>\n<ul>\n<li><a href=\"https://wordpress.org/plugins/limit-login-attempts/\">https://wordpress.org/plugins/limit-login-attempts/</a></li>\n<li><a href=\"https://wordpress.org/plugins/sucuri-scanner/\">https://wordpress.org/plugins/sucuri-scanner/</a></li>\n</ul>\n</li>\n</ol>\n<h2 id=\"Final-Thoughts\"><a href=\"#Final-Thoughts\" aria-label=\"Final Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Final Thoughts</h2>\n<p>The list above is by no means exhaustive, and it's just based on things I've been learning the past couple of weeks. I am very open to correction, addition, or subtraction, from the above by anyone with more experience. While I don't plan on focusing primarily on Wordpress, I'm learning more and more <code class=\"language-text\">LA</code> of the <code class=\"language-text\">LAMP</code> stack through this experience, and at the end of the day, with my interest in <code class=\"language-text\">Gatsby</code>, I probably will be involved more and more with the ecosystem. </p>\n<p>That being said, <strong><em>there is nothing wrong with learning more about website security.</em></strong> </p>\n<p>Even if static sites are the future, keeping our CMS and web-servers safe should not become lost or remain assumed knowledge.</p>","id":"fe8ad5f0-ba88-5703-bdcb-3e65cd4181ff","timeToRead":9,"frontmatter":{"date":"2019-09-20","path":"/blog/wordpress-security-lessons-learned.html","tags":["wordpress","security","apache","htaccess","viruses","linux","permissions"],"title":"Cleaning Up Wordpress: Lessons Learned in Website Security","featuredAlt":"Someone holding a laptop with 'You've been hacked!' displayed upon the screen","redirect_from":null}}],"touch events":[{"excerpt":"In my recent blog post on Using React Hooks to set up Infinite Scroll, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.622814321398835%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGki8kMEwM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAQIRAAMSMTL/2gAIAQEAAQUCmAt1ijtkxo9Hf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECEBFB/9oACAEBAAY/AjZIbprmV//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IXU+h2aUrswOe8mgta8TYf/aAAwDAQACAAMAAAAQF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/ECOTf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFxgf/aAAgBAQABPxDGd0WpWqyLV1cVhbY8mMBm3waeIAA0M//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        title=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        src=\"/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg\"\n        srcset=\"/static/9262257e3e1dba7123eb7236d14248d8/afcd2/butterfly-finger.jpg 300w,\n/static/9262257e3e1dba7123eb7236d14248d8/82472/butterfly-finger.jpg 600w,\n/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg 1200w,\n/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>In my recent blog post on <a href=\"/blog/infinite-scroll-mobile-desktop-gatsby.html\">Using React Hooks to set up Infinite Scroll</a>, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into production, <strong>some of the links on my page stopped working</strong>. I tried debugging my CSS, to no avail, only to realize the solution involved updating my <code class=\"language-text\">touchend</code> event handlers with a very simple fix.</p>\n<h2 id=\"Solution-Debugging-CSS-\"><a href=\"#Solution-Debugging-CSS-\" aria-label=\"Solution Debugging CSS  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging CSS ??</h2>\n<p>The structure of my components nests some links within block level elements. To achieve infinite-scrolling, I map over a list of businesses as follows:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>govId<span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Link \n<span class=\"gatsby-highlight-code-line\">      to<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/businesses/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">}</span></span>      state<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> \n        prevPath<span class=\"token punctuation\">:</span> <span class=\"token keyword\">typeof</span> window <span class=\"token operator\">!==</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">undefined</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>pathname <span class=\"token punctuation\">:</span> <span class=\"token string\">''</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>businessName<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">tel:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessPhone<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>businessPhone<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p>From past experience, I immediately thought the solution would be to either adjust the <code class=\"language-text\">z-index</code> of the nested link or to set <code class=\"language-text\">pointer-events</code> on the parent elements. I tried both:</p>\n<div class=\"gatsby-highlight\" data-language=\"css\"><pre class=\"language-css\"><code class=\"language-css\">    <span class=\"token selector\">li, li>h2, p</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token property\">pointer-events</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token selector\">li>h2>a, p>a</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 3<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Neither solution solved the problem nor were a problem to begin with, at least in my implementation. </p>\n<h2 id=\"Solution-Debugging-touchend-Event-Handler-\"><a href=\"#Solution-Debugging-touchend-Event-Handler-\" aria-label=\"Solution Debugging touchend Event Handler  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging <code class=\"language-text\">touchend</code> Event Handler !!</h2>\n<p>First, here is the initial state of my code for this component. I define <code class=\"language-text\">handleScroll</code> to add more items to the infinite scroll. Then, <code class=\"language-text\">handleTouchEnd</code> calls the scroll event handler to avoid double loading. Take particular note of <code class=\"language-text\">e.preventDefault</code> (perhaps this shouldn’t be called at all? We shall find out soon enough):</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// function to add more items to the infinite scroll until no items left</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>businesses<span class=\"token punctuation\">,</span> hasMore<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>After realizing that updated my <code class=\"language-text\">css</code> would not resolve my issue, I wondered what in the world is causing my problem. In this particular component, I use two <code class=\"language-text\">React</code> hooks to manage state and handle events - <code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code>. I wondered, </p>\n<blockquote>\n<p>Okay, so this is a <code class=\"language-text\">Gatsby</code> project, and I'm importing the <code class=\"language-text\">Link</code> component from the gatsby library. Could these hooks be interfering with the functionality of the <code class=\"language-text\">Link</code>?</p>\n</blockquote>\n<p>This wasn’t the problem. I could see in the console that <code class=\"language-text\">Link</code> rendered a simple <code class=\"language-text\">a</code> tag, and other <code class=\"language-text\">Link</code> components were working on the page, such as those rendered by the <code class=\"language-text\">Navigation</code> component. The only links not working were within my infinite scrolling list component. Moreover, the links worked perfectly in a desktop environment. So I again wondered,</p>\n<blockquote>\n<p>Why in the world does this work on desktop and not on mobile? No errors are being thrown. The <code class=\"language-text\">href</code> attribute is valid and working if I paste it in the browser. How again does the <code class=\"language-text\">touchend</code> event work?</p>\n</blockquote>\n<p>This led me to investigating the order in which events are fired by touch screens.</p>\n<h3 id=\"click-comes-after-touchend\"><a href=\"#click-comes-after-touchend\" aria-label=\"click comes after touchend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><code class=\"language-text\">click</code> comes after <code class=\"language-text\">touchend</code></h3>\n<p>According to MDN, the W3C standard calls for <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent#Event_order\">a <em>typical</em> order of events fired by touch screens</a>, as follows:</p>\n<ul>\n<li><code class=\"language-text\">touchstart</code></li>\n<li>Zero or more <code class=\"language-text\">touchmove</code> events, depending on movement of the finger(s)</li>\n<li><code class=\"language-text\">touchend</code></li>\n<li><code class=\"language-text\">mousemove</code></li>\n<li><code class=\"language-text\">mousedown</code></li>\n<li><code class=\"language-text\">mouseup</code></li>\n<li><code class=\"language-text\">click</code></li>\n</ul>\n<p>Remember I asked you to take particular note that I was calling <code class=\"language-text\">e.preventDefault()</code> on the <code class=\"language-text\">touchend</code> event? Turns out that is the culprit. By cancelling the dispatching of further events on <code class=\"language-text\">touchend</code>, the <code class=\"language-text\">click</code> event for the link component was never being fired. As MDN tells us:</p>\n<blockquote>\n<p>If the <code class=\"language-text\">touchstart</code>, <code class=\"language-text\">touchmove</code> or <code class=\"language-text\">touchend</code> event is canceled during an interaction, <em>no mouse or click events will be fired</em>.</p>\n</blockquote>\n<p>The solution then must include not calling <code class=\"language-text\">e.preventDefault</code>, particularly when a link is the target of <code class=\"language-text\">touchend</code>.</p>\n<p>So, the only change necessary involves adding a condition within my <code class=\"language-text\">handleTouchEnd</code> function, to check for <code class=\"language-text\">a</code> tags, or <code class=\"language-text\">Element.tagName == &quot;A&quot;</code>, and only call <code class=\"language-text\">e.preventDefault()</code> if the target is not such a tag:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>tagName <span class=\"token operator\">!==</span> <span class=\"token string\">\"A\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"this makes me a click event, most likely\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p>Photo by <a href=\"https://unsplash.com/@amyjoyhumphries\">Amy Humphries</a> on <a href=\"https://unsplash.com/\">Unsplash</a></p>\n</blockquote>","id":"ca6c2a6a-a6ff-550f-b6a9-e027abd7fb45","timeToRead":4,"frontmatter":{"date":"2019-06-10","path":"/blog/improving-touch-events-upon-infinite-scrolling-component.html","tags":["touch events","react","infinite scroll","production","gatsby link"],"title":"Improving Touch Events upon an Infinite Scrolling Component","featuredAlt":"Closeup of a butterfly sitting on the tip of the someone's index finger","redirect_from":null}}],"react":[{"excerpt":"In my recent blog post on Using React Hooks to set up Infinite Scroll, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.622814321398835%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGki8kMEwM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAQIRAAMSMTL/2gAIAQEAAQUCmAt1ijtkxo9Hf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECEBFB/9oACAEBAAY/AjZIbprmV//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IXU+h2aUrswOe8mgta8TYf/aAAwDAQACAAMAAAAQF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/ECOTf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFxgf/aAAgBAQABPxDGd0WpWqyLV1cVhbY8mMBm3waeIAA0M//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        title=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        src=\"/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg\"\n        srcset=\"/static/9262257e3e1dba7123eb7236d14248d8/afcd2/butterfly-finger.jpg 300w,\n/static/9262257e3e1dba7123eb7236d14248d8/82472/butterfly-finger.jpg 600w,\n/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg 1200w,\n/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>In my recent blog post on <a href=\"/blog/infinite-scroll-mobile-desktop-gatsby.html\">Using React Hooks to set up Infinite Scroll</a>, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into production, <strong>some of the links on my page stopped working</strong>. I tried debugging my CSS, to no avail, only to realize the solution involved updating my <code class=\"language-text\">touchend</code> event handlers with a very simple fix.</p>\n<h2 id=\"Solution-Debugging-CSS-\"><a href=\"#Solution-Debugging-CSS-\" aria-label=\"Solution Debugging CSS  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging CSS ??</h2>\n<p>The structure of my components nests some links within block level elements. To achieve infinite-scrolling, I map over a list of businesses as follows:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>govId<span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Link \n<span class=\"gatsby-highlight-code-line\">      to<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/businesses/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">}</span></span>      state<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> \n        prevPath<span class=\"token punctuation\">:</span> <span class=\"token keyword\">typeof</span> window <span class=\"token operator\">!==</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">undefined</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>pathname <span class=\"token punctuation\">:</span> <span class=\"token string\">''</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>businessName<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">tel:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessPhone<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>businessPhone<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p>From past experience, I immediately thought the solution would be to either adjust the <code class=\"language-text\">z-index</code> of the nested link or to set <code class=\"language-text\">pointer-events</code> on the parent elements. I tried both:</p>\n<div class=\"gatsby-highlight\" data-language=\"css\"><pre class=\"language-css\"><code class=\"language-css\">    <span class=\"token selector\">li, li>h2, p</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token property\">pointer-events</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token selector\">li>h2>a, p>a</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 3<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Neither solution solved the problem nor were a problem to begin with, at least in my implementation. </p>\n<h2 id=\"Solution-Debugging-touchend-Event-Handler-\"><a href=\"#Solution-Debugging-touchend-Event-Handler-\" aria-label=\"Solution Debugging touchend Event Handler  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging <code class=\"language-text\">touchend</code> Event Handler !!</h2>\n<p>First, here is the initial state of my code for this component. I define <code class=\"language-text\">handleScroll</code> to add more items to the infinite scroll. Then, <code class=\"language-text\">handleTouchEnd</code> calls the scroll event handler to avoid double loading. Take particular note of <code class=\"language-text\">e.preventDefault</code> (perhaps this shouldn’t be called at all? We shall find out soon enough):</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// function to add more items to the infinite scroll until no items left</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>businesses<span class=\"token punctuation\">,</span> hasMore<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>After realizing that updated my <code class=\"language-text\">css</code> would not resolve my issue, I wondered what in the world is causing my problem. In this particular component, I use two <code class=\"language-text\">React</code> hooks to manage state and handle events - <code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code>. I wondered, </p>\n<blockquote>\n<p>Okay, so this is a <code class=\"language-text\">Gatsby</code> project, and I'm importing the <code class=\"language-text\">Link</code> component from the gatsby library. Could these hooks be interfering with the functionality of the <code class=\"language-text\">Link</code>?</p>\n</blockquote>\n<p>This wasn’t the problem. I could see in the console that <code class=\"language-text\">Link</code> rendered a simple <code class=\"language-text\">a</code> tag, and other <code class=\"language-text\">Link</code> components were working on the page, such as those rendered by the <code class=\"language-text\">Navigation</code> component. The only links not working were within my infinite scrolling list component. Moreover, the links worked perfectly in a desktop environment. So I again wondered,</p>\n<blockquote>\n<p>Why in the world does this work on desktop and not on mobile? No errors are being thrown. The <code class=\"language-text\">href</code> attribute is valid and working if I paste it in the browser. How again does the <code class=\"language-text\">touchend</code> event work?</p>\n</blockquote>\n<p>This led me to investigating the order in which events are fired by touch screens.</p>\n<h3 id=\"click-comes-after-touchend\"><a href=\"#click-comes-after-touchend\" aria-label=\"click comes after touchend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><code class=\"language-text\">click</code> comes after <code class=\"language-text\">touchend</code></h3>\n<p>According to MDN, the W3C standard calls for <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent#Event_order\">a <em>typical</em> order of events fired by touch screens</a>, as follows:</p>\n<ul>\n<li><code class=\"language-text\">touchstart</code></li>\n<li>Zero or more <code class=\"language-text\">touchmove</code> events, depending on movement of the finger(s)</li>\n<li><code class=\"language-text\">touchend</code></li>\n<li><code class=\"language-text\">mousemove</code></li>\n<li><code class=\"language-text\">mousedown</code></li>\n<li><code class=\"language-text\">mouseup</code></li>\n<li><code class=\"language-text\">click</code></li>\n</ul>\n<p>Remember I asked you to take particular note that I was calling <code class=\"language-text\">e.preventDefault()</code> on the <code class=\"language-text\">touchend</code> event? Turns out that is the culprit. By cancelling the dispatching of further events on <code class=\"language-text\">touchend</code>, the <code class=\"language-text\">click</code> event for the link component was never being fired. As MDN tells us:</p>\n<blockquote>\n<p>If the <code class=\"language-text\">touchstart</code>, <code class=\"language-text\">touchmove</code> or <code class=\"language-text\">touchend</code> event is canceled during an interaction, <em>no mouse or click events will be fired</em>.</p>\n</blockquote>\n<p>The solution then must include not calling <code class=\"language-text\">e.preventDefault</code>, particularly when a link is the target of <code class=\"language-text\">touchend</code>.</p>\n<p>So, the only change necessary involves adding a condition within my <code class=\"language-text\">handleTouchEnd</code> function, to check for <code class=\"language-text\">a</code> tags, or <code class=\"language-text\">Element.tagName == &quot;A&quot;</code>, and only call <code class=\"language-text\">e.preventDefault()</code> if the target is not such a tag:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>tagName <span class=\"token operator\">!==</span> <span class=\"token string\">\"A\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"this makes me a click event, most likely\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p>Photo by <a href=\"https://unsplash.com/@amyjoyhumphries\">Amy Humphries</a> on <a href=\"https://unsplash.com/\">Unsplash</a></p>\n</blockquote>","id":"ca6c2a6a-a6ff-550f-b6a9-e027abd7fb45","timeToRead":4,"frontmatter":{"date":"2019-06-10","path":"/blog/improving-touch-events-upon-infinite-scrolling-component.html","tags":["touch events","react","infinite scroll","production","gatsby link"],"title":"Improving Touch Events upon an Infinite Scrolling Component","featuredAlt":"Closeup of a butterfly sitting on the tip of the someone's index finger","redirect_from":null}},{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}}],"infinite scroll":[{"excerpt":"In my recent blog post on Using React Hooks to set up Infinite Scroll, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.622814321398835%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGki8kMEwM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAQIRAAMSMTL/2gAIAQEAAQUCmAt1ijtkxo9Hf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECEBFB/9oACAEBAAY/AjZIbprmV//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IXU+h2aUrswOe8mgta8TYf/aAAwDAQACAAMAAAAQF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/ECOTf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFxgf/aAAgBAQABPxDGd0WpWqyLV1cVhbY8mMBm3waeIAA0M//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        title=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        src=\"/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg\"\n        srcset=\"/static/9262257e3e1dba7123eb7236d14248d8/afcd2/butterfly-finger.jpg 300w,\n/static/9262257e3e1dba7123eb7236d14248d8/82472/butterfly-finger.jpg 600w,\n/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg 1200w,\n/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>In my recent blog post on <a href=\"/blog/infinite-scroll-mobile-desktop-gatsby.html\">Using React Hooks to set up Infinite Scroll</a>, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into production, <strong>some of the links on my page stopped working</strong>. I tried debugging my CSS, to no avail, only to realize the solution involved updating my <code class=\"language-text\">touchend</code> event handlers with a very simple fix.</p>\n<h2 id=\"Solution-Debugging-CSS-\"><a href=\"#Solution-Debugging-CSS-\" aria-label=\"Solution Debugging CSS  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging CSS ??</h2>\n<p>The structure of my components nests some links within block level elements. To achieve infinite-scrolling, I map over a list of businesses as follows:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>govId<span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Link \n<span class=\"gatsby-highlight-code-line\">      to<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/businesses/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">}</span></span>      state<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> \n        prevPath<span class=\"token punctuation\">:</span> <span class=\"token keyword\">typeof</span> window <span class=\"token operator\">!==</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">undefined</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>pathname <span class=\"token punctuation\">:</span> <span class=\"token string\">''</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>businessName<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">tel:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessPhone<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>businessPhone<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p>From past experience, I immediately thought the solution would be to either adjust the <code class=\"language-text\">z-index</code> of the nested link or to set <code class=\"language-text\">pointer-events</code> on the parent elements. I tried both:</p>\n<div class=\"gatsby-highlight\" data-language=\"css\"><pre class=\"language-css\"><code class=\"language-css\">    <span class=\"token selector\">li, li>h2, p</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token property\">pointer-events</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token selector\">li>h2>a, p>a</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 3<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Neither solution solved the problem nor were a problem to begin with, at least in my implementation. </p>\n<h2 id=\"Solution-Debugging-touchend-Event-Handler-\"><a href=\"#Solution-Debugging-touchend-Event-Handler-\" aria-label=\"Solution Debugging touchend Event Handler  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging <code class=\"language-text\">touchend</code> Event Handler !!</h2>\n<p>First, here is the initial state of my code for this component. I define <code class=\"language-text\">handleScroll</code> to add more items to the infinite scroll. Then, <code class=\"language-text\">handleTouchEnd</code> calls the scroll event handler to avoid double loading. Take particular note of <code class=\"language-text\">e.preventDefault</code> (perhaps this shouldn’t be called at all? We shall find out soon enough):</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// function to add more items to the infinite scroll until no items left</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>businesses<span class=\"token punctuation\">,</span> hasMore<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>After realizing that updated my <code class=\"language-text\">css</code> would not resolve my issue, I wondered what in the world is causing my problem. In this particular component, I use two <code class=\"language-text\">React</code> hooks to manage state and handle events - <code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code>. I wondered, </p>\n<blockquote>\n<p>Okay, so this is a <code class=\"language-text\">Gatsby</code> project, and I'm importing the <code class=\"language-text\">Link</code> component from the gatsby library. Could these hooks be interfering with the functionality of the <code class=\"language-text\">Link</code>?</p>\n</blockquote>\n<p>This wasn’t the problem. I could see in the console that <code class=\"language-text\">Link</code> rendered a simple <code class=\"language-text\">a</code> tag, and other <code class=\"language-text\">Link</code> components were working on the page, such as those rendered by the <code class=\"language-text\">Navigation</code> component. The only links not working were within my infinite scrolling list component. Moreover, the links worked perfectly in a desktop environment. So I again wondered,</p>\n<blockquote>\n<p>Why in the world does this work on desktop and not on mobile? No errors are being thrown. The <code class=\"language-text\">href</code> attribute is valid and working if I paste it in the browser. How again does the <code class=\"language-text\">touchend</code> event work?</p>\n</blockquote>\n<p>This led me to investigating the order in which events are fired by touch screens.</p>\n<h3 id=\"click-comes-after-touchend\"><a href=\"#click-comes-after-touchend\" aria-label=\"click comes after touchend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><code class=\"language-text\">click</code> comes after <code class=\"language-text\">touchend</code></h3>\n<p>According to MDN, the W3C standard calls for <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent#Event_order\">a <em>typical</em> order of events fired by touch screens</a>, as follows:</p>\n<ul>\n<li><code class=\"language-text\">touchstart</code></li>\n<li>Zero or more <code class=\"language-text\">touchmove</code> events, depending on movement of the finger(s)</li>\n<li><code class=\"language-text\">touchend</code></li>\n<li><code class=\"language-text\">mousemove</code></li>\n<li><code class=\"language-text\">mousedown</code></li>\n<li><code class=\"language-text\">mouseup</code></li>\n<li><code class=\"language-text\">click</code></li>\n</ul>\n<p>Remember I asked you to take particular note that I was calling <code class=\"language-text\">e.preventDefault()</code> on the <code class=\"language-text\">touchend</code> event? Turns out that is the culprit. By cancelling the dispatching of further events on <code class=\"language-text\">touchend</code>, the <code class=\"language-text\">click</code> event for the link component was never being fired. As MDN tells us:</p>\n<blockquote>\n<p>If the <code class=\"language-text\">touchstart</code>, <code class=\"language-text\">touchmove</code> or <code class=\"language-text\">touchend</code> event is canceled during an interaction, <em>no mouse or click events will be fired</em>.</p>\n</blockquote>\n<p>The solution then must include not calling <code class=\"language-text\">e.preventDefault</code>, particularly when a link is the target of <code class=\"language-text\">touchend</code>.</p>\n<p>So, the only change necessary involves adding a condition within my <code class=\"language-text\">handleTouchEnd</code> function, to check for <code class=\"language-text\">a</code> tags, or <code class=\"language-text\">Element.tagName == &quot;A&quot;</code>, and only call <code class=\"language-text\">e.preventDefault()</code> if the target is not such a tag:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>tagName <span class=\"token operator\">!==</span> <span class=\"token string\">\"A\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"this makes me a click event, most likely\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p>Photo by <a href=\"https://unsplash.com/@amyjoyhumphries\">Amy Humphries</a> on <a href=\"https://unsplash.com/\">Unsplash</a></p>\n</blockquote>","id":"ca6c2a6a-a6ff-550f-b6a9-e027abd7fb45","timeToRead":4,"frontmatter":{"date":"2019-06-10","path":"/blog/improving-touch-events-upon-infinite-scrolling-component.html","tags":["touch events","react","infinite scroll","production","gatsby link"],"title":"Improving Touch Events upon an Infinite Scrolling Component","featuredAlt":"Closeup of a butterfly sitting on the tip of the someone's index finger","redirect_from":null}},{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}}],"production":[{"excerpt":"In my recent blog post on Using React Hooks to set up Infinite Scroll, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.622814321398835%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGki8kMEwM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAQIRAAMSMTL/2gAIAQEAAQUCmAt1ijtkxo9Hf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECEBFB/9oACAEBAAY/AjZIbprmV//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IXU+h2aUrswOe8mgta8TYf/aAAwDAQACAAMAAAAQF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/ECOTf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFxgf/aAAgBAQABPxDGd0WpWqyLV1cVhbY8mMBm3waeIAA0M//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        title=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        src=\"/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg\"\n        srcset=\"/static/9262257e3e1dba7123eb7236d14248d8/afcd2/butterfly-finger.jpg 300w,\n/static/9262257e3e1dba7123eb7236d14248d8/82472/butterfly-finger.jpg 600w,\n/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg 1200w,\n/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>In my recent blog post on <a href=\"/blog/infinite-scroll-mobile-desktop-gatsby.html\">Using React Hooks to set up Infinite Scroll</a>, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into production, <strong>some of the links on my page stopped working</strong>. I tried debugging my CSS, to no avail, only to realize the solution involved updating my <code class=\"language-text\">touchend</code> event handlers with a very simple fix.</p>\n<h2 id=\"Solution-Debugging-CSS-\"><a href=\"#Solution-Debugging-CSS-\" aria-label=\"Solution Debugging CSS  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging CSS ??</h2>\n<p>The structure of my components nests some links within block level elements. To achieve infinite-scrolling, I map over a list of businesses as follows:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>govId<span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Link \n<span class=\"gatsby-highlight-code-line\">      to<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/businesses/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">}</span></span>      state<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> \n        prevPath<span class=\"token punctuation\">:</span> <span class=\"token keyword\">typeof</span> window <span class=\"token operator\">!==</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">undefined</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>pathname <span class=\"token punctuation\">:</span> <span class=\"token string\">''</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>businessName<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">tel:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessPhone<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>businessPhone<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p>From past experience, I immediately thought the solution would be to either adjust the <code class=\"language-text\">z-index</code> of the nested link or to set <code class=\"language-text\">pointer-events</code> on the parent elements. I tried both:</p>\n<div class=\"gatsby-highlight\" data-language=\"css\"><pre class=\"language-css\"><code class=\"language-css\">    <span class=\"token selector\">li, li>h2, p</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token property\">pointer-events</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token selector\">li>h2>a, p>a</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 3<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Neither solution solved the problem nor were a problem to begin with, at least in my implementation. </p>\n<h2 id=\"Solution-Debugging-touchend-Event-Handler-\"><a href=\"#Solution-Debugging-touchend-Event-Handler-\" aria-label=\"Solution Debugging touchend Event Handler  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging <code class=\"language-text\">touchend</code> Event Handler !!</h2>\n<p>First, here is the initial state of my code for this component. I define <code class=\"language-text\">handleScroll</code> to add more items to the infinite scroll. Then, <code class=\"language-text\">handleTouchEnd</code> calls the scroll event handler to avoid double loading. Take particular note of <code class=\"language-text\">e.preventDefault</code> (perhaps this shouldn’t be called at all? We shall find out soon enough):</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// function to add more items to the infinite scroll until no items left</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>businesses<span class=\"token punctuation\">,</span> hasMore<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>After realizing that updated my <code class=\"language-text\">css</code> would not resolve my issue, I wondered what in the world is causing my problem. In this particular component, I use two <code class=\"language-text\">React</code> hooks to manage state and handle events - <code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code>. I wondered, </p>\n<blockquote>\n<p>Okay, so this is a <code class=\"language-text\">Gatsby</code> project, and I'm importing the <code class=\"language-text\">Link</code> component from the gatsby library. Could these hooks be interfering with the functionality of the <code class=\"language-text\">Link</code>?</p>\n</blockquote>\n<p>This wasn’t the problem. I could see in the console that <code class=\"language-text\">Link</code> rendered a simple <code class=\"language-text\">a</code> tag, and other <code class=\"language-text\">Link</code> components were working on the page, such as those rendered by the <code class=\"language-text\">Navigation</code> component. The only links not working were within my infinite scrolling list component. Moreover, the links worked perfectly in a desktop environment. So I again wondered,</p>\n<blockquote>\n<p>Why in the world does this work on desktop and not on mobile? No errors are being thrown. The <code class=\"language-text\">href</code> attribute is valid and working if I paste it in the browser. How again does the <code class=\"language-text\">touchend</code> event work?</p>\n</blockquote>\n<p>This led me to investigating the order in which events are fired by touch screens.</p>\n<h3 id=\"click-comes-after-touchend\"><a href=\"#click-comes-after-touchend\" aria-label=\"click comes after touchend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><code class=\"language-text\">click</code> comes after <code class=\"language-text\">touchend</code></h3>\n<p>According to MDN, the W3C standard calls for <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent#Event_order\">a <em>typical</em> order of events fired by touch screens</a>, as follows:</p>\n<ul>\n<li><code class=\"language-text\">touchstart</code></li>\n<li>Zero or more <code class=\"language-text\">touchmove</code> events, depending on movement of the finger(s)</li>\n<li><code class=\"language-text\">touchend</code></li>\n<li><code class=\"language-text\">mousemove</code></li>\n<li><code class=\"language-text\">mousedown</code></li>\n<li><code class=\"language-text\">mouseup</code></li>\n<li><code class=\"language-text\">click</code></li>\n</ul>\n<p>Remember I asked you to take particular note that I was calling <code class=\"language-text\">e.preventDefault()</code> on the <code class=\"language-text\">touchend</code> event? Turns out that is the culprit. By cancelling the dispatching of further events on <code class=\"language-text\">touchend</code>, the <code class=\"language-text\">click</code> event for the link component was never being fired. As MDN tells us:</p>\n<blockquote>\n<p>If the <code class=\"language-text\">touchstart</code>, <code class=\"language-text\">touchmove</code> or <code class=\"language-text\">touchend</code> event is canceled during an interaction, <em>no mouse or click events will be fired</em>.</p>\n</blockquote>\n<p>The solution then must include not calling <code class=\"language-text\">e.preventDefault</code>, particularly when a link is the target of <code class=\"language-text\">touchend</code>.</p>\n<p>So, the only change necessary involves adding a condition within my <code class=\"language-text\">handleTouchEnd</code> function, to check for <code class=\"language-text\">a</code> tags, or <code class=\"language-text\">Element.tagName == &quot;A&quot;</code>, and only call <code class=\"language-text\">e.preventDefault()</code> if the target is not such a tag:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>tagName <span class=\"token operator\">!==</span> <span class=\"token string\">\"A\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"this makes me a click event, most likely\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p>Photo by <a href=\"https://unsplash.com/@amyjoyhumphries\">Amy Humphries</a> on <a href=\"https://unsplash.com/\">Unsplash</a></p>\n</blockquote>","id":"ca6c2a6a-a6ff-550f-b6a9-e027abd7fb45","timeToRead":4,"frontmatter":{"date":"2019-06-10","path":"/blog/improving-touch-events-upon-infinite-scrolling-component.html","tags":["touch events","react","infinite scroll","production","gatsby link"],"title":"Improving Touch Events upon an Infinite Scrolling Component","featuredAlt":"Closeup of a butterfly sitting on the tip of the someone's index finger","redirect_from":null}}],"gatsby link":[{"excerpt":"In my recent blog post on Using React Hooks to set up Infinite Scroll, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.622814321398835%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGki8kMEwM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAQIRAAMSMTL/2gAIAQEAAQUCmAt1ijtkxo9Hf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECEBFB/9oACAEBAAY/AjZIbprmV//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IXU+h2aUrswOe8mgta8TYf/aAAwDAQACAAMAAAAQF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/ECOTf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFxgf/aAAgBAQABPxDGd0WpWqyLV1cVhbY8mMBm3waeIAA0M//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        title=\"Closeup of a butterfly sitting on the tip of the someone&#39;s index finger\"\n        src=\"/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg\"\n        srcset=\"/static/9262257e3e1dba7123eb7236d14248d8/afcd2/butterfly-finger.jpg 300w,\n/static/9262257e3e1dba7123eb7236d14248d8/82472/butterfly-finger.jpg 600w,\n/static/9262257e3e1dba7123eb7236d14248d8/c35de/butterfly-finger.jpg 1200w,\n/static/9262257e3e1dba7123eb7236d14248d8/de376/butterfly-finger.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>In my recent blog post on <a href=\"/blog/infinite-scroll-mobile-desktop-gatsby.html\">Using React Hooks to set up Infinite Scroll</a>, I created a working version of infinite scroll that works in both desktop and touch screen environments. However, I came across a problem I did not anticipate when I put it into production, <strong>some of the links on my page stopped working</strong>. I tried debugging my CSS, to no avail, only to realize the solution involved updating my <code class=\"language-text\">touchend</code> event handlers with a very simple fix.</p>\n<h2 id=\"Solution-Debugging-CSS-\"><a href=\"#Solution-Debugging-CSS-\" aria-label=\"Solution Debugging CSS  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging CSS ??</h2>\n<p>The structure of my components nests some links within block level elements. To achieve infinite-scrolling, I map over a list of businesses as follows:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>govId<span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Link \n<span class=\"gatsby-highlight-code-line\">      to<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/businesses/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">}</span></span>      state<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> \n        prevPath<span class=\"token punctuation\">:</span> <span class=\"token keyword\">typeof</span> window <span class=\"token operator\">!==</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">undefined</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">?</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>pathname <span class=\"token punctuation\">:</span> <span class=\"token string\">''</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>businessName<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">tel:</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>businessPhone<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>businessPhone<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p>From past experience, I immediately thought the solution would be to either adjust the <code class=\"language-text\">z-index</code> of the nested link or to set <code class=\"language-text\">pointer-events</code> on the parent elements. I tried both:</p>\n<div class=\"gatsby-highlight\" data-language=\"css\"><pre class=\"language-css\"><code class=\"language-css\">    <span class=\"token selector\">li, li>h2, p</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token property\">pointer-events</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token selector\">li>h2>a, p>a</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 3<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Neither solution solved the problem nor were a problem to begin with, at least in my implementation. </p>\n<h2 id=\"Solution-Debugging-touchend-Event-Handler-\"><a href=\"#Solution-Debugging-touchend-Event-Handler-\" aria-label=\"Solution Debugging touchend Event Handler  permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Solution: Debugging <code class=\"language-text\">touchend</code> Event Handler !!</h2>\n<p>First, here is the initial state of my code for this component. I define <code class=\"language-text\">handleScroll</code> to add more items to the infinite scroll. Then, <code class=\"language-text\">handleTouchEnd</code> calls the scroll event handler to avoid double loading. Take particular note of <code class=\"language-text\">e.preventDefault</code> (perhaps this shouldn’t be called at all? We shall find out soon enough):</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// function to add more items to the infinite scroll until no items left</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span>      <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n      window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>businesses<span class=\"token punctuation\">,</span> hasMore<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>After realizing that updated my <code class=\"language-text\">css</code> would not resolve my issue, I wondered what in the world is causing my problem. In this particular component, I use two <code class=\"language-text\">React</code> hooks to manage state and handle events - <code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code>. I wondered, </p>\n<blockquote>\n<p>Okay, so this is a <code class=\"language-text\">Gatsby</code> project, and I'm importing the <code class=\"language-text\">Link</code> component from the gatsby library. Could these hooks be interfering with the functionality of the <code class=\"language-text\">Link</code>?</p>\n</blockquote>\n<p>This wasn’t the problem. I could see in the console that <code class=\"language-text\">Link</code> rendered a simple <code class=\"language-text\">a</code> tag, and other <code class=\"language-text\">Link</code> components were working on the page, such as those rendered by the <code class=\"language-text\">Navigation</code> component. The only links not working were within my infinite scrolling list component. Moreover, the links worked perfectly in a desktop environment. So I again wondered,</p>\n<blockquote>\n<p>Why in the world does this work on desktop and not on mobile? No errors are being thrown. The <code class=\"language-text\">href</code> attribute is valid and working if I paste it in the browser. How again does the <code class=\"language-text\">touchend</code> event work?</p>\n</blockquote>\n<p>This led me to investigating the order in which events are fired by touch screens.</p>\n<h3 id=\"click-comes-after-touchend\"><a href=\"#click-comes-after-touchend\" aria-label=\"click comes after touchend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><code class=\"language-text\">click</code> comes after <code class=\"language-text\">touchend</code></h3>\n<p>According to MDN, the W3C standard calls for <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent#Event_order\">a <em>typical</em> order of events fired by touch screens</a>, as follows:</p>\n<ul>\n<li><code class=\"language-text\">touchstart</code></li>\n<li>Zero or more <code class=\"language-text\">touchmove</code> events, depending on movement of the finger(s)</li>\n<li><code class=\"language-text\">touchend</code></li>\n<li><code class=\"language-text\">mousemove</code></li>\n<li><code class=\"language-text\">mousedown</code></li>\n<li><code class=\"language-text\">mouseup</code></li>\n<li><code class=\"language-text\">click</code></li>\n</ul>\n<p>Remember I asked you to take particular note that I was calling <code class=\"language-text\">e.preventDefault()</code> on the <code class=\"language-text\">touchend</code> event? Turns out that is the culprit. By cancelling the dispatching of further events on <code class=\"language-text\">touchend</code>, the <code class=\"language-text\">click</code> event for the link component was never being fired. As MDN tells us:</p>\n<blockquote>\n<p>If the <code class=\"language-text\">touchstart</code>, <code class=\"language-text\">touchmove</code> or <code class=\"language-text\">touchend</code> event is canceled during an interaction, <em>no mouse or click events will be fired</em>.</p>\n</blockquote>\n<p>The solution then must include not calling <code class=\"language-text\">e.preventDefault</code>, particularly when a link is the target of <code class=\"language-text\">touchend</code>.</p>\n<p>So, the only change necessary involves adding a condition within my <code class=\"language-text\">handleTouchEnd</code> function, to check for <code class=\"language-text\">a</code> tags, or <code class=\"language-text\">Element.tagName == &quot;A&quot;</code>, and only call <code class=\"language-text\">e.preventDefault()</code> if the target is not such a tag:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>tagName <span class=\"token operator\">!==</span> <span class=\"token string\">\"A\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"this makes me a click event, most likely\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p>Photo by <a href=\"https://unsplash.com/@amyjoyhumphries\">Amy Humphries</a> on <a href=\"https://unsplash.com/\">Unsplash</a></p>\n</blockquote>","id":"ca6c2a6a-a6ff-550f-b6a9-e027abd7fb45","timeToRead":4,"frontmatter":{"date":"2019-06-10","path":"/blog/improving-touch-events-upon-infinite-scrolling-component.html","tags":["touch events","react","infinite scroll","production","gatsby link"],"title":"Improving Touch Events upon an Infinite Scrolling Component","featuredAlt":"Closeup of a butterfly sitting on the tip of the someone's index finger","redirect_from":null}}],"development":[{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}},{"excerpt":"I was drawn to Gatsby out of my love for React, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as  was taking off. It was a challenge at first to…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.456286427976686%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABenOzxcwzP//EABcQAQEBAQAAAAAAAAAAAAAAAAABAgT/2gAIAQEAAQUC6JdNK20r/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAARECEiD/2gAIAQEABj8CFZJa/8QAGxAAAQQDAAAAAAAAAAAAAAAAAQARITEQQYH/2gAIAQEAAT8hf5dwCOJfqtnsv//aAAwDAQACAAMAAAAQOz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQIBAT8QVkz/xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhENH/2gAIAQEAAT8QkAKol+66ej2CJljY9c1tfD//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Gatsby loves to claim to produce the fastest sites around\"\n        title=\"Gatsby loves to claim to produce the fastest sites around\"\n        src=\"/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg\"\n        srcset=\"/static/d580489e8877a5a2439959d5d0b2b3cd/afcd2/gatsby-stickers.jpg 300w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/82472/gatsby-stickers.jpg 600w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg 1200w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I was drawn to <a href=\"https://www.gatsbyjs.org/\">Gatsby</a> out of my love for <a href=\"https://reactjs.org/\">React</a>, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as <code class=\"language-text\">create-react-app</code> was taking off. It was a challenge at first to learn the simplicity of proxying to get the front end to run concurrently with a <code class=\"language-text\">node</code> / <code class=\"language-text\">express</code> API. And yet, to get from that point to server-side rendering took a little more research and effort. It has been fun learning with and from the larger coding community. I could continue to enumerate the other technical issues I have encountered and solved, and yet some others I still have to learn, but note something important so far regarding my journey—it has been a <em>techinical-first-journey</em>, focused on knowledge and skill of the various langauges and libraries, necessary yes, but perhaps not primary. The last thing on mind has been <strong>SEO</strong>, <strong>accessbility</strong>, and <strong>security</strong>.</p>\n<h2 id=\"Setting-An-SEO-First-Mindset\"><a href=\"#Setting-An-SEO-First-Mindset\" aria-label=\"Setting An SEO First Mindset permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting An SEO-First Mindset</h2>\n<p>I’ll leave accessibility and then security future posts, but what has impressed me thus far in my dive into the <code class=\"language-text\">Gatbsy</code> ecosystem has been <strong>the ease to configure search engine optimization</strong>. In fact, you can create an architecture for your site or app that is SEO driven long before developing your UI. I want to walk you through the things I have learned so far in optimizing a Gatsby site for SEO right from the start.</p>\n<h3 id=\"Before-We-Begin\"><a href=\"#Before-We-Begin\" aria-label=\"Before We Begin permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><em>Before We Begin</em></h3>\n<p>You need to have some familiarity with Gatsby. To learn how to install the <code class=\"language-text\">gatbsy-cli</code> and create a new Gatsby project from one of the many Gatsby Starters, please consider <a href=\"https://www.gatsbyjs.org/tutorial/\">completing the Gatsby tutorial</a>.</p>\n<p>Otherwise, <a href=\"https://www.gatsbyjs.org/starters/?c=SEO&#x26;v=2\">pick a starter</a> from the SEO category, and open the SEO component or just use the <code class=\"language-text\">gatsby-starter-default</code> by running from the command line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  gatsby new seo-blog https://github.com/gatsbyjs/gatsby-starter-default</code></pre></div>\n<p>The SEO component is dependent upon <code class=\"language-text\">react-helmet</code>, if your starter does not come with SEO initialized be sure to add it. We also want to add some other features like sitemap, google analytics, and RSS feed, for syndication. Finally, we need to create <code class=\"language-text\">robots.txt</code> to manage how search engines crawl the site. I’ve split up the commands below for spacing purposes, but they can all run as one <code class=\"language-text\">yarn add</code> command:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> react-helmet gatsby-plugin-react-helmet \n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-feed gatsby-plugin-google-analytics gatsby-plugin-sitemap\n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-robots-txt</code></pre></div>\n<p>With your starter and these plugins installed, we are ready to set up our site for SEO Performance.</p>\n<h3 id=\"Setting-up-gatsby-configjs\"><a href=\"#Setting-up-gatsby-configjs\" aria-label=\"Setting up gatsby configjs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting up <code class=\"language-text\">gatsby-config.js</code></h3>\n<p>Within the root of your new Gatsby project sits the file Gatsby uses to configure  <code class=\"language-text\">siteMetaData</code> and <code class=\"language-text\">plugins</code> and <a href=\"https://www.gatsbyjs.org/docs/gatsby-config/\">several other important features</a>.</p>\n<p>This file, <code class=\"language-text\">gatsby-config.js</code> is going to do the heavy lifting of importing all your vital SEO related content into GraphQL or create necessary files directly (like <code class=\"language-text\">robots.txt</code>).</p>\n<h4 id=\"Site-Metadata\"><a href=\"#Site-Metadata\" aria-label=\"Site Metadata permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Site Metadata</h4>\n<p>Metadata is as it sounds, data that extends across or throughout the entirity of your site. It can be used anywhere, but will come most in handy when configuring your SEO component as well as Google Structured Data.</p>\n<p>Initialize your metadata as an Object literal with key/value pairs that can be converted into <code class=\"language-text\">&lt;meta&gt;</code> tags, or can be passed to sitemaps or footers, wherever you might need global site data: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\">  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>title<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site will blow your mind with radical content, extravagant colors, and hip designs.<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span></code></pre></div>\n<p>Here is where you need to plan what might use across your site:</p>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> title</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> description</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> keywords</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> site verification</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> social links</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" disabled> other</li>\n</ul>\n<p>With <code class=\"language-text\">siteMetadata</code> set up, your can now query this data to be used within your plugin initialization, even within the same <code class=\"language-text\">gatsby-config.js</code> file. I’ve organized my <code class=\"language-text\">siteMetadata</code> so that I can make the following query:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    site {\n      siteMetadata {\n        title\n        description\n        author\n        siteUrl\n        siteVerification {\n          google\n          bing\n        }\n        social {\n          twitter\n        }\n        socialLinks {\n          twitter\n          linkedin\n          facebook\n          stackOverflow\n          github\n          instagram\n          pinterest\n          youtube\n          email\n          phone\n          fax\n          address\n        }\n        keywords\n        organization {\n          name\n          url\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span></code></pre></div>\n<p>This query returns an object matching this query structure:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  site<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      title<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      description<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      author<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteUrl<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteVerification<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        google<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        bing<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      social<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      socialLinks<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        linkedin<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        facebook<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        stackOverflow<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        github<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        instagram<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        pinterest<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        youtube<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        email<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        phone<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        fax<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        address<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      keywords<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>String<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n      organization<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        name<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        url<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h4 id=\"Plugin-Setup\"><a href=\"#Plugin-Setup\" aria-label=\"Plugin Setup permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Plugin Setup</h4>\n<p>We are going to focus on four plugins, each for the sitemap, RSS feed, robots.txt file, and Google Analytics (for tracking the SEO success of your site). We’ll initialize the plugins immediately following <code class=\"language-text\">siteMetaData</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/** SEE ABOVE **/</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span> </span><span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">/** An ARRAY **/</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> </span>  <span class=\"token punctuation\">}</span></code></pre></div>\n<ol>\n<li><strong>gatsby-plugin-sitemap</strong></li>\n</ol>\n<p>The sitemap plugin can be used simply or with options. Generally, you want to include anything and everything with high quality content, and <strong><em>exclude duplicate content, thin content, or pages behind authentication</em></strong>. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/creating-a-sitemap/\">detailed walkthrough for setting up your sitemap</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-sitemap</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">          exclude<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/admin</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/tags/links</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">]</span></span>        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span></code></pre></div>\n<ol start=\"2\">\n<li><strong>gatsby-plugin-feed</strong></li>\n</ol>\n<p><strong><em>An RSS feed helps with syndication of content on your site, like if you had a blog and wanted to cross-post to another better established blog, and it helps communicate changes to your site to search engines.</em></strong> This plugin allows you to create any number of different feeds utlizing the power of GraphQL to query your data. Some of what is below is dependent on how you structure your pages and posts in <code class=\"language-text\">gatsby-node.js</code>. The feed will walk through each of your pages in <code class=\"language-text\">markdown</code> generate an XML RSS Feed. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/adding-an-rss-feed/\">detailed walkthrough for adding an RSS feed</a>. </p>\n<p><strong><em>Note particularly the use of queries below to complete the feed.</em></strong></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">// graphQL query to get siteMetadata</span></span><span class=\"gatsby-highlight-code-line\">      query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">        {</span><span class=\"gatsby-highlight-code-line\">          site {</span><span class=\"gatsby-highlight-code-line\">            siteMetadata {</span><span class=\"gatsby-highlight-code-line\">              title</span><span class=\"gatsby-highlight-code-line\">              description</span><span class=\"gatsby-highlight-code-line\">              siteUrl</span><span class=\"gatsby-highlight-code-line\">              site_url: siteUrl,</span><span class=\"gatsby-highlight-code-line\">              author</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">        }</span><span class=\"gatsby-highlight-code-line\">      </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>      feeds<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token comment\">// an array of feeds, I just have one below</span>\n        <span class=\"token punctuation\">{</span>\n          <span class=\"token function-variable function\">serialize</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> query<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> site<span class=\"token punctuation\">,</span> allMarkdownRemark <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> siteMetadata <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> siteUrl <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> site<span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">return</span> allMarkdownRemark<span class=\"token punctuation\">.</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">edge</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n              <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> \n                node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> \n                  frontmatter<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                    title<span class=\"token punctuation\">,</span> \n                    date<span class=\"token punctuation\">,</span> \n                    path<span class=\"token punctuation\">,</span> \n                    author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> name<span class=\"token punctuation\">,</span> email <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featured<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> publicURL <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featuredAlt\n                  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                  excerpt<span class=\"token punctuation\">,</span> \n                  html\n                <span class=\"token punctuation\">}</span> \n              <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> edge<span class=\"token punctuation\">;</span>\n              <span class=\"token keyword\">return</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">assign</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> edge<span class=\"token punctuation\">.</span>node<span class=\"token punctuation\">.</span>frontmatter<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n                language<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">en-us</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                title<span class=\"token punctuation\">,</span>\n                description<span class=\"token punctuation\">:</span> excerpt<span class=\"token punctuation\">,</span>\n                date<span class=\"token punctuation\">,</span>\n                url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                guid<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                author<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>email<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> ( </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>name<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> )</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                image<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                  url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> publicURL<span class=\"token punctuation\">,</span>\n                  title<span class=\"token punctuation\">:</span> featuredAlt<span class=\"token punctuation\">,</span>\n                  link<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                custom_elements<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> <span class=\"token string\">\"content:encoded\"</span><span class=\"token punctuation\">:</span> html <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n              <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token comment\">// query to get blog post data</span></span><span class=\"gatsby-highlight-code-line\">          query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">          {</span><span class=\"gatsby-highlight-code-line\">            allMarkdownRemark(</span><span class=\"gatsby-highlight-code-line\">              sort: { order: DESC, fields: [frontmatter___date] },</span><span class=\"gatsby-highlight-code-line\">            ) {</span><span class=\"gatsby-highlight-code-line\">              edges {</span><span class=\"gatsby-highlight-code-line\">                node {</span><span class=\"gatsby-highlight-code-line\">                  excerpt</span><span class=\"gatsby-highlight-code-line\">                  html</span><span class=\"gatsby-highlight-code-line\">                  frontmatter {</span><span class=\"gatsby-highlight-code-line\">                    path</span><span class=\"gatsby-highlight-code-line\">                    date</span><span class=\"gatsby-highlight-code-line\">                    title</span><span class=\"gatsby-highlight-code-line\">                    featured {</span><span class=\"gatsby-highlight-code-line\">                      publicURL</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                    featuredAlt</span><span class=\"gatsby-highlight-code-line\">                    author {</span><span class=\"gatsby-highlight-code-line\">                      name</span><span class=\"gatsby-highlight-code-line\">                      email</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                  }</span><span class=\"gatsby-highlight-code-line\">                }</span><span class=\"gatsby-highlight-code-line\">              }</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">          </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>          output<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/rss.xml\"</span><span class=\"token punctuation\">,</span>\n          title<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">My Awesome Site | RSS Feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li><strong>gatsby-plugin-robots-txt</strong></li>\n</ol>\n<p>With <code class=\"language-text\">robots.txt</code> files, you can instruct crawlers to ignore your site and/or individual paths, based on certain conditions. <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-robots-txt/?=robots\">See the plugin description for more detailed use cases</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token string\">'gatsby-plugin-robots-txt'</span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      policy<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> userAgent<span class=\"token punctuation\">:</span> <span class=\"token string\">'*'</span><span class=\"token punctuation\">,</span> allow<span class=\"token punctuation\">:</span> <span class=\"token string\">'/'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span></span>    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"4\">\n<li><strong>gatsby-plugin-google-analytics</strong></li>\n</ol>\n<p>Google analytics will help you track how users find and interact with your site, so you can manage and update your site over time for better SEO results. Verify your site with Google and store your analytics key here:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-google-analytics</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      trackingId<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<h3 id=\"Optimizing-the-SEO-Component\"><a href=\"#Optimizing-the-SEO-Component\" aria-label=\"Optimizing the SEO Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing the SEO Component</h3>\n<p>The secret sauce behind the SEO Component is the well-known <code class=\"language-text\">react-hemlet</code> package. Every page and every template imports the SEO Component and thus you can pass specific information to adjust the metadata for each public facing page.</p>\n<p>Use your imagination—what can you pass to this component to create the perfect SEO enabled page? Is the page a landing page, a blog post, a media gallery, a video, a professional profile, a product? There are 614 types of schemas listed on <a href=\"https://schema.org/docs/schemas.html\">https://schema.org</a>. You can pass specific schema related information to the SEO component.</p>\n<p>If any of these values you pass to the component, a <code class=\"language-text\">StaticQuery</code> would fill in what’s missing with <code class=\"language-text\">siteMetaData</code>. From this data, <code class=\"language-text\">react-helmet</code> creates all the <code class=\"language-text\">&lt;meta&gt;</code> tags, including <code class=\"language-text\">open graph</code> and <code class=\"language-text\">twitter</code> card tags, and pass relevant data to another component that returns <code class=\"language-text\">Google Structured Data</code>.</p>\n<p>Rather than including a long code-snippet, refer back to the <a href=\"#Before-We-Begin\">Before We Begin</a> section, or <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-react-helmet/\">refer to the <code class=\"language-text\">gatsby-plugin-react-helment</code> page for installation</a>. But please note, the structure of my SEO Component follows that outlined by <a href=\"https://blog.dustinschau.com/search-engine-optimization-with-gatsby\">this excellent post</a> by Dustin Schau.</p>\n<p>As I have tinkered with the SEO Component, here are the features I added:</p>\n<ol>\n<li>Additional Fields Passed to Component to:  distinguish between types of pages, such as blog posts, to handle authors of content other than main site author, and to handle changes in date modified for pages and posts. More could be added in the future.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    description<span class=\"token punctuation\">,</span>\n    lang<span class=\"token punctuation\">,</span>\n    meta<span class=\"token punctuation\">,</span>\n    keywords<span class=\"token punctuation\">,</span>\n    image<span class=\"token punctuation\">,</span>\n    title<span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// highlight start</span>\n    pathname<span class=\"token punctuation\">,</span>\n    isBlogPost<span class=\"token punctuation\">,</span>\n    author<span class=\"token punctuation\">,</span>\n    datePublished <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    dateModified <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span>\n    <span class=\"token comment\">// highlight-end</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></code></pre></div>\n<ol start=\"2\">\n<li>Setting <code class=\"language-text\">og:type</code> conditionally</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    property<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">og:type</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> isBlogPost <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">article</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">website</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </code></pre></div>\n<ol start=\"3\">\n<li>Always setting an <code class=\"language-text\">alt</code> property on the image object</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\">  <span class=\"token comment\">// ALWAYS ADD IMAGE:ALT</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span></code></pre></div>\n<ol start=\"4\">\n<li>Handling Secure Images</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token comment\">// handle Secure Image</span></span><span class=\"gatsby-highlight-code-line\">    metaImage <span class=\"token operator\">&amp;&amp;</span> metaImage<span class=\"token punctuation\">.</span><span class=\"token function\">indexOf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"https\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token operator\">-</span><span class=\"token number\">1</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">?</span> <span class=\"token punctuation\">[</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">            property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:secure_url\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">            content<span class=\"token punctuation\">:</span> metaImage<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span> property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:secure_url\"</span><span class=\"token punctuation\">,</span> content<span class=\"token punctuation\">:</span> metaImage <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token punctuation\">]</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span>  <span class=\"token punctuation\">)</span></code></pre></div>\n<ol start=\"5\">\n<li>Adding a Component to handle <code class=\"language-text\">Google Structured Data</code> using <a href=\"https://schema.org\">schema.org</a> categories. I came across an example of such a component from reading through various documentation and articles, I can’t recall where I saw the link first, but I borrowed and adapted <a href=\"https://github.com/jlengstorf/gatsby-theme-jason-blog/blob/e6d25ca927afdc75c759e611d4ba6ba086452bb8/src/components/SEO/SchemaOrg.js\">from Jason Lengstorf</a>. I made two small adaptations to his excellent work.</li>\n</ol>\n<h3 id=\"Configuring-the-SchemaOrg-Component\"><a href=\"#Configuring-the-SchemaOrg-Component\" aria-label=\"Configuring the SchemaOrg Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Configuring the SchemaOrg Component</h3>\n<p>You will import and call the <code class=\"language-text\">SchemaOrg</code> Component from within the <code class=\"language-text\">SEO</code> Component and place it just after the closing tag of the <code class=\"language-text\">Helmet</code> Component and pass the following properties:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token operator\">...</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">...</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Fragment Shorthand */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">&lt;</span>Helmet \n          <span class=\"token punctuation\">{</span><span class=\"token comment\">/* All the Meta Tag Configuration */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>SchemaOrg</span><span class=\"gatsby-highlight-code-line\">          isBlogPost<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          url<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          title<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          image<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaImage<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          description<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaDescription<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          datePublished<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>datePublished<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          dateModified<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>dateModified<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          canonicalUrl<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>siteUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          author<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost <span class=\"token operator\">?</span> author <span class=\"token punctuation\">:</span> siteMetadata<span class=\"token punctuation\">.</span>author<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          organization<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>organization<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          defaultTitle<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>I won’t copy and paste the entire <code class=\"language-text\">SchemaOrg</code> Component here. Grab it from the link above, and give Jason Lengstorf some credit in your code. Below are the few additions I made:</p>\n<ol>\n<li>I added author email to the Schema. This will come from <code class=\"language-text\">siteMetadata</code> for most pages and from post <code class=\"language-text\">frontmatter</code> from blog posts. This will support multiple authors for your site and each page can reflect that uniquely if you so choose.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Person\"</span><span class=\"token punctuation\">,</span>\n    name<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    email<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>email<span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"2\">\n<li>I updated the organization logo from a simple URI to an <code class=\"language-text\">ImageObject</code> type. While the <code class=\"language-text\">String</code> URI is acceptable to the <code class=\"language-text\">Organization</code> type, Google has specific expectations and was throwing an error until I changed it to an <code class=\"language-text\">ImageObject</code>. </li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  publisher<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Organization\"</span><span class=\"token punctuation\">,</span>\n    url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    logo<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"ImageObject\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      width<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>width<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      height<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>height<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span>    name<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li>Add <code class=\"language-text\">dataModified</code> to reflect changes to the page after initial publication for the <code class=\"language-text\">BlogPosting</code> type.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  datePublished<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">  dateModified<span class=\"token punctuation\">,</span></span></code></pre></div>\n<p>When you have more complexity within you site, you can pass flags to this Component to return differing types of schema as needed. But no matter what you do, do not put your site into production without first passing through the <code class=\"language-text\">script</code> generated by the component to the <a href=\"https://search.google.com/structured-data/testing-tool/u/0/\">Google Structured Data Testing Tool</a>.</p>\n<h2 id=\"Concluding-Thoughts\"><a href=\"#Concluding-Thoughts\" aria-label=\"Concluding Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Concluding Thoughts</h2>\n<p>When I configured my site according to the plan I outlined above, not only do I get image rich, descriptive Social Sharing cards, I get perfect SEO scores when running a Lighthouse Audit on my site:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 816px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 17.15686274509804%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAmUlEQVQI1z2N2w6CMBBE+f+/88H4YGJURAEpvdDL0lLGdo1OMtmzmexss+87qiYn8bYzc9wSWtVj3SLvs9eQxVUhEh5qwJq+mbQeiydmIkLzK7yMLZuPVsLhfoIj/89uU8fsY8CxO/PTqqsY0UnB7JxDU6GW2sWyq1JMUFKVGTkzxpRsQc4ZIQRorWHLM1OKxNBDPF/wpaxmH1t76BizOlMxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        title=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        src=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n        srcset=\"/static/384cdb474a81538eeda376637170d853/135ae/lighthouse_audit_seo.png 300w,\n/static/384cdb474a81538eeda376637170d853/34e8a/lighthouse_audit_seo.png 600w,\n/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png 816w\"\n        sizes=\"(max-width: 816px) 100vw, 816px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You also see that I scored 100% for Accessibility on my site. This is so easy to score with Gatsby as well, and I’ll talk about what I learned on this topic in the future.</p>\n<p>Cross-Posted: <a href=\"https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g\">https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g</a></p>","id":"fc7a6836-1cdc-519e-8c65-39beae2150c8","timeToRead":10,"frontmatter":{"date":"2019-04-20","path":"/blog/seo-accessibility-first-gatsby.html","tags":["gatsby","development","seo"],"title":"Putting SEO First with Gatsby","featuredAlt":"Gatsby loves to claim to produce the fastest sites around","redirect_from":null}},{"excerpt":"Changing careers is tough.  For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.539550374687764%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABSy6MV5lEf//EABwQAAIBBQEAAAAAAAAAAAAAAAECAAMREiEiM//aAAgBAQABBQINSnJawMX1bRyIn//EABURAQEAAAAAAAAAAAAAAAAAABEA/9oACAEDAQE/AVm//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BR//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhMTJS/9oACAEBAAY/AslKsGxBXLf/xAAcEAACAgIDAAAAAAAAAAAAAAAAARExIWGhseH/2gAIAQEAAT8hRw3nRKuZ7LEuBZVq8KCJSVScH//aAAwDAQACAAMAAAAQ99//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQMBAT8QSJMf/8QAFhEBAQEAAAAAAAAAAAAAAAAAABFR/9oACAECAQE/EIrX/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARITFRcYH/2gAIAQEAAT8QDKbViX7BgkAyl1W3yFrM6UcQjVscfZgKoItBvYZVbHA8T//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        title=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        src=\"/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg\"\n        srcset=\"/static/30874b6095537c9af16ed94f9b05bc86/afcd2/bootcamp-graduation.jpg 300w,\n/static/30874b6095537c9af16ed94f9b05bc86/82472/bootcamp-graduation.jpg 600w,\n/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg 1200w,\n/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>Changing careers is tough. </p>\n<p>For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees one obtains come higher-level and yet more narrow opportunities. Such opportunities fade into nothing if just can’t break-in your desired field. </p>\n<p>Over the past three years I have received several phone calls, emails, and direct messages asking me for advice, whether or not one of my friends or their loved ones should consider a career change like I did. </p>\n<p>There are a lot of very talented, highly educated people stuck in low-paying, dead-end jobs, or who just can’t break in to their dream field. </p>\n<p>I’m writing this post for them and for the many others out there like them. I want to answer some of the most commonly asked questions I have received. I want to be specific to my particular set of choices, recognizing that everybody’s situation is different. I also want to humbly admit that I’m writing from a Western, middle class perspective. Not everyone is afforded the types of opportunities from which I have derived great benefit. This may look different for someone in a developing country, and the sets of choices you have will lean away from formal programs that cost a lot of money. If this is you reading this post, I sympathize with you and want to be an encouragement to you in any way I can. Hit me up <a href=\"https://twitter.com/wesleylhandy\">on twitter</a> and ask me any questions you got. </p>\n<p>This is the first post in a series on my decision to switch careers, attend a bootcamp, and land my first dev job. This post will cover the first two questions in the list below:</p>\n<h2 id=\"Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\"><a href=\"#Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\" aria-label=\"Questions Ill Answer to Aid Your Decision Making Process Through This Series permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Questions I’ll Answer to Aid Your Decision Making Process Through This Series</h2>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\">Why Should I Consider a Career Switch Into Web Development?</a></li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\">Why Should I Consider Attending a Web Development Bootcamp?</a></li>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n<li>How Long Does it Take to Land a Job After Bootcamp?</li>\n<li>What Mentality Must Someone Have To Find a Job in Tech?</li>\n</ul>\n<h2 id=\"Why-You-Could-Consider-a-Career-Change-into-Web-Development\"><a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\" aria-label=\"Why You Could Consider a Career Change into Web Development permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Could Consider a Career Change into Web Development</h2>\n<p>Web development is one field where you can break-in without a college degree majoring in some technological discipline. The need for developers, data scientists, cybersecurity specialists and many other types of programmers and developers is on the rise. Don’t miss something from that sentence. There are a wide variety of growing fields in the tech job market, of which web development is one. </p>\n<p>The job market is competitive, it takes a lot of effort, a lot of networking and building relationships and a little bit of luck to break into tech full-time, but it is possible because the resources to attain the skills necessary to do the job are readily available for free, with minimal cost, or sometimes with more than minimal cost. Nevertheless, switching careers is such a difficult task to undertake, you must be desparate for the change. You have to be willing to go all-in with time, money, effort, and focus. </p>\n<h3 id=\"Why-I-Had-to-Switch-Careers\"><a href=\"#Why-I-Had-to-Switch-Careers\" aria-label=\"Why I Had to Switch Careers permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Had to Switch Careers</h3>\n<p>The year was 2016; I found myself and my family in a desperate situation. We had moved to New Jersey/Metro New York as part of a Christian ministry, and we have moved without having a full-time job in place. At the time, having an earned PhD from an accredited instituion, I was teaching online for a couple of also-accredited schools. I was able to add to that a part-time gig teaching formal and informal logic, bible and theology at a private school. Honestly, I thought we could make it while I sought either regular Professorship or simply transitioning from my previous full-time job in academic administration to a new institution in the New York area. The NY/NJ MSA is home to hundreds of institutions of higher learning, certainly I could get one to hire me. Fast forward three years, a few hundred applications, a dozen or so interviews, being passed over as a finalist half of those times, and zippo offers.</p>\n<p>I was loving life serving a loving group of people as one of their pastors, but my family was just scraping by. The more time that passed, the more useless my resume became, as I had to explain my increasingly longer employment gap. We were on the brink of bankruptcy, and I needed marketable skills where I would be in demand. </p>\n<p>Before plunging headlong into the  humanities, I completed and enjoyed several years of computer science courses between high school and my first year of college, albeit twenty years prior and with languages like Basic, Pascal and Fortran. Still, even as I pursued philosophy and theology over coding and programming, I never lost my love for tech, becoming the de facto software trainer whatever job I found, culminating in my last academic job, which I loved, in Institutional Research,  where I got to play around with SQL queries and advanced Excel spreadsheet programming. It only made sense that I pursue something like web development. Moreover, I was living just a few miles from Silicon Alley - NY has a bustling tech scene and I wanted in, I needed in. </p>\n<p>I didn’t fully realize at the time all of what it was going to take to break in, but I was in desparate need and I knew that I could do it and would like doing it.</p>\n<h2 id=\"Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\"><a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\" aria-label=\"Why You Should Consider Attending a Web Development Bootcamp permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Should Consider Attending a Web Development Bootcamp</h2>\n<p>As a preface, let me once again express that I sympathize with those in economic situations where this is not a real possibility. Let me encourage you to look to all those who have worked hard to become quality self-taught programmers. They have put in the long hours and many, many months (sometimes years) to better themselves with marketable skills. I would highly recommend free online bootcamps like <a href=\"https://freecodecamp.org\">FreeCodeCamp</a> and edX courses like <a href=\"https://www.edx.org/course/cs50s-introduction-to-computer-science\">Harvard’s CS50</a></p>\n<p>Coding Bootcamps are designed to impart to students techinical training and programming skills that are valuable to employers. They are high-paced, very intense, and can take anywhere from 6 weeks to 6 months to complete. Most require significant pre-bootcamp coursework - usually the fundamentals of HTML/CSS/JavaScript or other primary coding languages. Depending on the duration of the program, they will require anywhere between 20 and 30 hours of time outside of class for homework and projects, and the more time you put in on, the better return you will have on the investment. They are not cheap. Some will offer free tuition in exchange for a hefty chunk of your salary from your first full-time gig, others want cash upfront, with costs ranging between $10,000 and $20,000. </p>\n<h3 id=\"Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\"><a href=\"#Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\" aria-label=\"Why I Chose to Take Out Loan for an In Person Bootcamp Experience permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose to Take Out Loan for an In-Person Bootcamp Experience</h3>\n<p>I chose to go into debt and pay to attend an in-person, intensive coding bootcamp. And, after going through the experience I still recommend it. Here are the reasons behind my decision:</p>\n<p><strong>First</strong>, I am an academic at heart, who loves teaching in the classroom, and yet I also have years of intense experience teaching and administering online courses. I know from experience that classrooms and face-to-face instruction/interaction seemed ideal for learning new stuff, especially new stuff that was going to lead to a new career. (Trust me, I know how impersonal and sometimes how downright crappy online instruction can be - get a bad curriculum or bad instructor or bad grader or a bad school just looking to turn a buck, and good luck!). </p>\n<p><strong>Second</strong>, I know myself. While I have no problem learning things independently, I also am a very eclectic and distracted learner. I can be reading Plato’s <em>Phaedrus</em> one day and watching <a href=\"https://www.youtube.com/user/periodicvideos\">Periodic Videos</a>, <a href=\"https://www.youtube.com/user/numberphile\">Numberphile</a> or <a href=\"https://www.youtube.com/channel/UC6107grRI4m0o2-emgoDnAA\">SmarterEveryDay</a> the next. I could see myself pouring into some online tutorials, and then getting sidetracked by Melville’s <em>Moby Dick</em> for a week or three. I needed a rigorous schedule with clear goals and guidelines. </p>\n<p><strong>Third</strong>, I know from experience and study the value of a learning community. We need people to challenge us, to push us, to correct us, and to interact with us, as humans, in general. Personally, I need people around me on the same journey. Online community is great, and the coding community on Twitter, blogs, Gitter, Slack, whereever is great, but still not the same as people in person.</p>\n<p><strong>Fourth</strong>, I desired some sort of organization that has connections with companies for job training and job placement. I didn’t know anyone who lived in my region who could help me get an <em>in</em> for a job. Most bootcamps have some sort of relationship with local and sometimes national and international businesses and they also have some sort of name recognition outside of those relationships. Moreover, I figured there would be previous graduates from the bootcamp who could be an advocate for an open position in my local area.</p>\n<h4 id=\"So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\"><a href=\"#So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\" aria-label=\"So then I had to choose which bootcamp would I seek to attend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>So, then I had to choose, which bootcamp would I seek to attend?</h4>\n<p>I knew nothing about recent technology or what to begin learning. My dev buddies mentioned things like Angular or React, which sounded eerily foreign to me at the time, even if they sounded like cool names for a night club. I always wanted to learn more MySQL, and I’d heard of Java, and JavaScript, though I didn’t know they weren’t even related languages to one another. </p>\n<p>Where to begin and which school was going to take me there? </p>\n<p>I found in my local area there were a few of bootcamps in Manhattan—The Flatiron School, General Assembly, Fullstack Academy, to name a few—but I found just one on the Jersey-side of the Hudson. They had started up a year earlier, graduating a few folks. I could check out their projects online. It was Rutgers Coding Bootcamp. </p>\n<p>Nothing against the programs I didn’t choose; plenty of folks jump into tech after completing those courses. I found that each of the programs all had similar curricula. I ended up choosing Rutgers, and I’m glad I did. </p>\n<p>If you live near a large city with major universities, odds are you will find a <a href=\"https://www.trilogyed.com/\">Trilogy Education Bootcamp</a>. Honestly, I can’t more highly recommend them. Of course as an alumnus of a bootcamp, I can sound biased. But I’m not saying any bootcamp is perfect. None are, but in spite of the imperfections here is why I chose to go with them at <a href=\"https://bootcamp.rutgers.edu/coding/\">Rutgers Coding Bootcamp</a>. Maybe some of my reasons will resonate with you.</p>\n<h2 id=\"Why-I-Chose-a-Bootcamp-by-Trilogy-Education\"><a href=\"#Why-I-Chose-a-Bootcamp-by-Trilogy-Education\" aria-label=\"Why I Chose a Bootcamp by Trilogy Education permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose a Bootcamp by Trilogy Education</h2>\n<p><strong>Financial Assistance</strong>: I really needed financial assistance to attend a bootcamp. I couldn&#x26;t afford to work for a discount after graduation, so the <em>free-now/pay-later scheme</em> was highly unattractive to me. Also, I had no assets to foot the bill on my own and I probably couldn’t qualify for an affordable personal loan. Most of the loans offered through other bootcamps were high interest (12–15%) and I wanted to take advantage of the fact that in the US, student loan interest can be tax deductible. Being connected to a major university, I could qualify for a student loan through Sallie Mae with a decent interest rate.</p>\n<p><strong>Relevant Curriculum</strong>: I asked my buddies to look at Rutger’s Curriculum and they all gave it a stamp of approval. They were teaching the newest tech that was in the most demand at the time. Moreover, the bootcamp advertised they were in constant communication with employers and updating their curriculum to fit the needs of the market. Trilogy continues to tweak its curriculum to meet local market needs, from a brief perusal over various programs around the country, and they are adding tracks in other in-demand fields like data science and cybersecurity. </p>\n<p><strong>Appropriate Pace</strong>: There are some bootcamps that require 40–60 hours per week of your time to complete, just in class! I found this undesirable for a couple of reasons. <em>Firstly</em>, there is only so much new content you can consume and internalize within a given period of time, especially if your goal is to master that material. At some point, the law of diminishing returns begins to apply. <em>Secondly</em>, I was already committed to 40+ hours of time between my teaching responsibilities and my ministry position. I could not give that much time, nor afford to stop working. What stood out about Rutgers is that they offered two timelines—a full-time twelve-week curriculum, or a twenty-four week flex curriculum. I preferred the longer curriculum to allow myself to dedicate between 20 and 30 hours outside of the ten hours of class time to learning and to also allow myself to continue to supplement my instruction with other training materials, books, and projects online. </p>\n<p><strong>Name Recognition</strong>: I’m sure employers are familiar with the various bootcamps in Manhattan, but Rutgers University has global name recognition. It’s a major research university, renowned for its academic standards (if not for it’s athletics). I have no clue where my career will take me in twenty years, but twenty years from now, who knows what bootcamps will still be around. My resume will always have Rutgers University attached to it. Even if the Bootcamp is in the Continuing Education department, I still have a certificate issued and sealed by the University. I’m a Rutger’s Alum. On LinkedIn, I rarely come across a job opening at a company that hasn’t hired a Rutger’s graduate - instant connection. </p>\n<h2 id=\"In-Conclusion\"><a href=\"#In-Conclusion\" aria-label=\"In Conclusion permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In Conclusion</h2>\n<p>I hope posting some of my own personal rationale behind my choices can be helpful to you. You will certainly have different circumstances and different criteria to base your decisions upon. I respect that.</p>\n<p>The next time I post in this series I want to handle the next three questions, though I might split it up even more:  </p>\n<ul>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n</ul>","id":"6e220122-4ed6-5aea-8f9a-ef9da266b59a","timeToRead":10,"frontmatter":{"date":"2019-04-10","path":"/blog/switching-careers-and-decisions-along-the-way.html","tags":["2ndCareerDev","development","bootcamp"],"title":"#2ndCareerDev - Switching Careers and Attending Bootcamp???","featuredAlt":"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017","redirect_from":null}},{"excerpt":"This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwACBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHjYtEUEP8A/8QAGxAAAgMAAwAAAAAAAAAAAAAAAQIAERIDBCH/2gAIAQEAAQUCtb62WVlzCcjj8WyZ/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEDAQE/ATF//8QAFxEBAAMAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAgEBPwGIDlf/xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIRITFh/9oACAEBAAY/AuNk04q/Sm9MwlRbP//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExUUH/2gAIAQEAAT8hK1J4EshDT4l0DhmIJu5HcwQi2y1n/9oADAMBAAIAAwAAABAcH//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxBLqL//xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAgBAgEBPxABX//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQWFRocH/2gAIAQEAAT8QWJfQg8dr6ioJ1ByR+k52ZRsu3UZ2ib0vEZnkR7jlCrVn/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Code displayed on a computer\"\n        title=\"Code displayed on a computer\"\n        src=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n        srcset=\"/static/41ced244a3d93044daa17132fdbf446a/afcd2/batman-coder.jpg 300w,\n/static/41ced244a3d93044daa17132fdbf446a/82472/batman-coder.jpg 600w,\n/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I was still hopeful, dreaming, a little naïve, yet expecting great things. I was ready to go to work and code hard! But that site did little more than highlight some of my work, projects that were good but not production quality. The page was overcoded - a single page with five sections but templated via <code class=\"language-text\">handlebars.js</code> (I should have been serving a single html file... <img class=\"emoji-icon\" alt=\"emoji-unamused\" data-icon=\"emoji-unamused\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAULUlEQVR4Ae2bBZAcR7auv5NZ1TCkIWkEHrGM1w5bqzVbZlhm3r3MjMvMcBn2MpuWmZkNWjPbAq9wmHqaqjLP6+rOuOrokMao9aMT+iOzqep8f57srKzW8P/j/+n4//H/QzjG8XYwr341GyPlVAyniLBZYKWx0o/SBYBQ9k5nFQ6p8hCeu1PhzquvZhfgj6kBbz820LL7NZypwnNjyxUmlpNtbLpMzmByghgB2+G9U9Qrvp7J4xJf9onekzi+KspnN/w3NwH6v3UF7HgOXUP9vNRYfjFXMOfZojGmy2LyGbgixiNWGxKQjlOroi6ToN7g64KveXzZ4Sre16v+B97xb1OzfBQoP2kGNJJ+wrGwQLR+lFdHsfxRrmh+xvZGmG6DLSgm9kg+hyn2Y/tWQ/cKpGslkutBTA4A9XW0XkLLh2BxHDd/AF+ZRWt1fGJwVcEvetxCSr3i70oT/bM9e7kaSJ+wAd+6iCcUq1dzZiHmvYUee2m0LCLqs0jeYQoRUf8oZuUZmJGnIT2bkcIgRF0gFoS2ihZQQB2kZbQ6jZYewo/9GH/oVtLZvfhqitYs6bwjnUupltw3qglvBG56Qgbc/0oeV5xwLbLrVfxhoUvekRuIu21/3GDzmK6IaORU7LorMMvPhOJggEsBDxqgBVCO0BfAgEQgQGUaP3ET7uGvko7diS+npGWDm02ozySL1bK+beM1/DmgP63vANnxEvqWF/nbQq99dTycI1pmsUVHtOJ47OYXYVacDVEBtA7qEDE8nlD1oVpykFbx4zfgHvoE6fgDuIolnXMkk3WqC+7qiQq/ve1jzAN6LA2QW57LqsFBrulaFl0Uj+SIeoWop9FuuhKz/kVIvh98FQEQeXxnUzqdQAFMAa3N4vc0TNj5FdJSnXRBScbqlOfSb09P86qtn+UgoE++AQF+eJBPF4bip+eX57G9EA0MEJ30CszIBaAJggeRJ3eN0XYjDEiMH/se6b3Xkc7M4BagNlGjOpXcPDnN8x+LCdGjhf/ylQw04K9rwq/M4IV4YIjolF9CBk5C3BwgIIBybAwARAHKmBVnEse9yN3/CnaKvM0DPH2Y5LpGri+46ivMAPpkGCCAOXElf10YiLbnV+SxfaYB30900mswfeshmQEx7fDHzAAAFMRVkMa5o5NfA/f+J8gseZ8Hr9tP1PSvgZ8DPKCP34AA/8Cr+cNin31VvCJH1G+JehvtxmchPaOQzrbg9YkDP2ZD0mozhywXHvg4Qh3vcxRTfdUDr3a3H381f/5IJsgjwf/wJTxt/YB8s7Cm0J1bnifqg2j0fMyay4AURBAA4acbGqhUgQi//+uke79POg/17Ptgf3Vxz4xecu7H+PFSJkRLwb9mhMKaXj6UH4q744GYqMdgB1Zihs8AvwgoEuifCgMEbfEjzZxsaRf4Q2gao1XXvSatf6jB8Mz/HqNKMOExGfCmy3hZscdujxrwtifGFA1m6GfAGnDlFrwIT2WIBhNshBk6FS1PYFMhGnAUF932N13mXvbf1/DfgD46AwL8G86krzsvr23C9zZUEEzPcPM6HldCREGfgpE/WiV4QbpGmjnaZALfGzdN6C75177hTP3M+25irs2EJQ0wgH3FZl6U77MnRH0RpthQ3iA9a0AU8eWlR/6pqgSJmjma8lQz5yz3fF96wis2py9qGPCfAd4tZYBkOmuQfG9Bfinqs5juCFswSD6PFJYhvgL48M6wrzfBjNSDV45pGIHIAIBXcAqaCYQEshzzeWxSw3dHZAy98+6XzhrU62+cxgVGXcoA+/7tbC12yTbbE2EKFpMzSK6ImAhcBWJpyOAWE8YmFplfqBNHhpUruukeLEDiwT3JRtjWORenqxwaXyRJPX29OUaWd2O749Y5E23mmOVqckkz94yh2JVse/923Xrxp/kR4JcywAB2pMc8N+6xzZsZNmeRyECUB3FQUCYPlvjKt37CTbceZHKiRK2WYozQ01fgrK1rePkLjmdZfx4Sz5MSsWFutsb1n3qAG2/ZT2m+ivdKPh8xvLyHM89YxZUXr2V4VQ9UfTPXLOcsd9dgyFhGengu+JsAB/gjGSCA2ThAXCzoxdK8k2OR2CCRYOIYTJ0vf+lhrv3EA0yNV+jKQV+PpW9ZjHOe+ekSH/v4/dx250He9fozGR7Mg9MnthuywuR4jbe8/yYevH+e4X7o78thraFeTTiwe4pr75/iK9/cyStfdDxXXbqumauPpJl7xpCxFAvpxRnbrhnS9mlgOg1429PYmC/ICbZokZzFNA2wYBz/dvXd/NWHbyct17jwik388huu5A//7KW89s9f1tTvvfcFvOQXn8ZUxbDjjkmwKfgauCq4MqQlSBcgmYdkFpKZTKE/33otLbXe66qtz9o0O1Z2zOaxs3OE8zXPneWQ5ZLllOWW5YhxSBRyz1kylowpYwvMcrQKsKO9nBrlTdHkDSZz0TZUiPjo5w9w7ccm2LptOa/8rbM5/ZQhqC9COUs6BRE2L89xzrbNvOJn1xFNH4K5faAe1AHa6qNHucCXw62Y0FqoGbZfsIxzn3cJfV0xVKpQnQRV6I04ZX0fV15xAbfdfTLX/t0NjRx30hMv56XP6EVqrsmQsWRMo73+VOCBpQww/UVzss0LEmfwBlOw3Pdgjf/4xATbr1jN77/+bPr8Ijx0N3gXAFPwSavF0Zcz4IHUdyyXnf2jXeOmoZuAKl2VChw8BHUPWJAITNxqxYCxnD46yMYPXsBfvv+GRq4HOG1zjhPXWmTRNFkypowN/KeOZoDJlI90k0SmBR8JiuHqz0+x4eRl/NFrj6N7+kFYSMAKqGsJbWMyUAckjOATvVktgANSbcGiQNIynHAOZ2HvAn29cTPH104sNnKe5V2/uTxUsSFjykfpJgJnpwESZGNhBZE0AaPIsHcsZfe08o53rKV7dg7m6mAEHG2jK8f+5xaRo9wkcUAKAHM1urXOH/z+Wt72tp3sH0s5rsdQtwKR0GQD28arpiPt2Eb0h/v2IFAT4Rd+dZTN/Q5mM3jTcSc3SMKhY4GctFrzJO9/DRC1nSMiYIAqYAw6V89ybeZcDQyIkDFlbEC85HeAEQpiQIAkVTasjtm8zKKTFRABPUwtQgAVXMUzOeOYnE1JHHQVDKMrI4p9BuoK+kQugAQSpTTvGJt2lMoeIzA8ELFqRQQWSBVVQKSZ62UnFUnnYpLpFAHEQMZ2tFVAQmuajOhh06spmpZRQEQDuyJ5AQ/3P1jjB7dVuPuhGhPTKUmiaCsTenotz7+kh2c3hHsEE6RjwE1rlOenE264s9ZYCivs2V9nsexxHghQJ27M8ysv7Gf1SIRP2k4wWcY4jwMAlDBgwYAgjTpmlHGeKg40LF/eC6IW2ipd8vDQroT//vwCd9xXQ7ynv8sw1CPkewURIfUwu+j454/O0NUFl1xQRGuKPIpilxjSFD71hTJf+GaJ6emU7pww2GtY0ydYC6pQTZS77qnw5yXHO39riGJO8G0rrTqHakPeg4MmGxjCMB5xL5B65tV71KUNCWgwQ0AQxMJXv1vhL64pUcgLmzbHDA1YSDyVCUd3HuIIFFhWFCKB7+5YbBhgELtEFUhojDC74HnP35W45Z6EDaMRZ2wt0l0UKlMOqbpmXwykTujJG/aMJdz/cIUzTsqhdUA1OODBJYHFk7EtdT9AAWopk03HfOaeQb1B8BCGv1pX6gPCn7xnkJO2RPT1QGwFZ5Uff7fKN/9rkUIsTROsgd68oKqoqRMMWDosTCwqZz4rzy+8vpc1I5ZCDGKF6Tnlk3+zwNyehL4+Q86C90oxEmo4kDqoQKBRrw25wOKbbEfbDWoQc3V5eHWiqFPw4SLHC2oApQn27PMN2AQWqjAbPhrB+WdHHNwTccuXE/p7hSTNDIPLLrNIsQ7lJZZID4TB27LJsGWrgXIFZhQSwMPKfsNzXhPxL+9PSaaVQh5m5pXjNkWceLKgSQoIhOOgLQZNFU20yQbK0aaAAunD837nCXWLd4r3HqMGQUEAA+Bx42HdsYBRMCCJYg6lPPfFluKQ5f4blWIBLr3ccM7pHiYdRMJRw7TNhGoKlfa1PkBNw+ig5TWvi/n6px2lSeW0cyOueGZMfyXF1xQxBoKZvsnvWyx1yNgAd7TtsAfSHxxk16VbfJXEF9QZ1HtAEAOIgnhQbfVtaMNrqpCfTXn2Mw1XPUewBqTmYNKH9zyGe/8EcOWwDOisZ/OAYfMfWOrOkENgfx2/qGDbLswcqA+VnHpczVczNkI9Hc2A5L/uZt8fPp2dhZqeomkoIQwCiNUA35I2JA2BIgQTHMi+lChuH10FeQwGSIcBntBK6xxTikw5ciJo2pBvuyuFEv61ck+0WRmlCjsztqUMUKC2mJCMzcsNQ5kBCeCDANohBCSIw22QgCoYWhKBYNAjXwcE0M7XVJD2xx7Uh745goEOSEEzVZSMaTFpEtUAPZoBCVD5+l7//eNHzS9EVTWuDqagrQTaDegEFwVzpLZDwCOvhQoKQR0RzJUj/A4ZitMr4BSXglaVtKo+YwIqQLLULTEPlP/8Zu57+Sl618igP83WBZ8YbF5AOkbTCEhbMib0/6clvA5AWyuPbhpoJiFEp/vt0yQMkKAecOBTRWseV/HZ8nlXxgSUAyNLGVCZT6jcdkA/fcVyf5pWDXQdLjmJBJEO0ACJ6XjOBNj2VUSAHGAB38ZSbxsboQOOYDaAtBVK6HgBD2hoXSj9mqILnowlY4JMSxug4U3zb/o+3zlr1O8ZXObXm6JgiiA5AzaMfDuQAQhQAtBeHW3J5wGn3HW7cMutcOiQYCNYv045c5syuglIBWqdS2QAQ8C29TWIpsLtCUHrHl/xuAXP3Izfk7EA84HtEX8YSYGFnXMs/Giv/tdV/f6tttvgi2DyQCxh/afdgKAATHslAKLQBT95CP79323TAOMhF4Eq3PA9+MTHle0XKa96tdLbB1Q7KkAEIFSNBFNaEg73NQFfBVdS3KwnY8hYoKkU4JEMUKAEzP7GN/jODav8Lat63VbpalWBiQ1YQSwgtJkR1DlNTQYv3PIj+Ju/MLiysHEYuvJCFPhSBwtV5dtfhp0Pev7otcrKNUCl3QQBCKa2jbwE8EwphHlPOucYm/S3ZAzALFB6LD+O1oDZuSrL/vE2/bvX9bm/k6IpSF6II4+xBiIQETAdJgDQNvpdcPctyl9+yNBrhZGVQj4CS9uuLYZCJHQXYO9ewwff63nLO5WBAYF6MAA6oIMJTlAFdeCrnmRRG/Ce6rSrZrk3GOaDATWOEJajhwOiGw7gL1hpamt79EwTC5kkAqy0TDBtJgjBhAAfw/SE8KH3CFSE/oJggKgI+WVQHIJcD3gDSR2SKuRjGBuHvQeEc88XBA4fWAQI0kxh3tdaa71fUNyMJx13/PBB/vH3v6nfBw4Bk0D6WA3wQdH19+mBF29gpD+vm4ilBR0FIySY8D/wbUtdTviXf1Bu+SGsHRVO22644GWG7S+B854D2y6DMy6FrY12yznCik1CPYH5Sbjtdli9GjacaCAR0GBE+3xPQevgy+DnlaQBXx9L2fmw/+qlH9F/B8aCyo/nv8iE7wKmgeJrPq//9OkX+RUj1p2OQGxArEEQVDRrA3iAF6U2DwenhGf/nOU5rxBWH6dQ91DRML8VgJwIXcPK6Khw7uWGe+8SPvofnvv3eC7xbaUf+jhpglMXtKz4ed+ET8Yd4/v9bVmuwAwwHRj08RgA4ML8ie+bJv/LX9YP/uuz3FtWwEmEnNQLxhnIAzFIFFYAhVwMb31fjkKvwoKDgwqqR7gQEkiABQXxnLTR8LYPRFRnFSoelPZRh0TQGviKz8q+BT+Wwbt7sxwbuR4CxkPujiXC8siRAh7gJ/PIbWPcetGwbuw2uiosRYi2rcuASKsvQOQV5hVqAHKEq7jQp+2LrQKUlMgDTsCZMOqgGXwZtORJ55Q0gz+YcuAn/tZf+aK+//v72N827xcBnqgBAHVAMzVM0K/t5MeXjNDfJ7pJwqCKV8haFTSAiSdA0g7dZlaQtgkB3wImFciAM9UFquAXFZ1vwbspT3LI8dAe/7WXfEb/ujE4B9rg5wCeLAMAaoAHdLqG/NPt3H7msMyNWHeqSYlU2+ZoMAMIpnSs23T0tcOItCVNQZO2b/kSuAx+RpvzvXworX7vfv758uv1mulKE3oMmAilz5NtQDABF4wwH71X9yU1dhxf1JEur6s0vNJsnYAnvFtQ1wboASX0MwEp4AJ4PRNoVdEyLfAFj5vzJFOedMxxYK+/5S9/qB/6o2/qTcBUgA8jjx7T/y0O9AJDQQNFS+/fXcW5F22QF/YPmw12mcH2GkyXIEXB5oCcIDFgQUz75gZQwCsaDGvt2hVXDyNfVlypZcDspN/97d36yd/6Mj+sOBaAGWAqaAHQn9afzPQAy4ABoB/oW9NDz7svYts5o3Ll0ICcGvUYyUywXQbJC5IDCXuJTMYAgA/gaNjB1VutK/smfFryOjWtd/5on37lzd9mx/4SJQhXeDATRr30VPzNUD5UQ18woTcYE/3+NjY8a4vZtmFAt/X0sj5XNHmTFwhXkiZqr4Cwf0+BcAurXvG10gJ7ds/Iji886Hf85Q52A2kAXQjw86Ffeyr/aMoAxQAfRBfQDeQtmOccz4rto6w5YciMDnfp6q6YwXxET2zJAySOWi2lVE6YnizLgfun/N7v7mX/5x5g3IEPgItAOQAHte/vn/qIAvxKYBNwKnAmsB24DHgm8Bzg+cBzgRcAz8sU+s8Nrz0nvPey8Nkzw7E2hWP3AhH/G0cURn8IWANsBk4GTg8w5wDnBbh2nRdeOzO89+Tw2TXhWN3HAlw4diFA3KEotO37RwBtW14TIA1tu/RYJfnTis47B53nVsAHBTOOffwvrHvsx5swbgQAAAAASUVORK5CYII=\" title=\"emoji-unamused\"> ) I had plans on creating a <code class=\"language-text\">mongodb</code> backed blog, and for two years, you would find in the footer of my site <em>Blog Coming Soon</em>. <img class=\"emoji-icon\" alt=\"emoji-thumbsdown\" data-icon=\"emoji-thumbsdown\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAATlUlEQVR4Xu1beaymV1l/zjnv+q33fneZlelMW6hdgRJKKS02RjYjRozyjyEhwZigYmJM/MMQ4op/EIhxCYsgxASNFtCgrQiKCZSyWWXaaaG1Mx1mOnefb//effF3nnPovbkw3juGNumVb/K7513PfM/vWc9z7qUffX6EH+H/NcR+Hnrf2+5aJq+1XOXlkqR6rqKikydZmCazKp7E63GcX0wmg/Mfe2zc/0Hvf+Adb+iVorzNVf6rhBA3K0fd4Ch1wlGyWUsRKiEdwqeua6rKgso8pzROsiyeRbPxZH06nZ6ZJek3hVRfvP5Vd66EftNVdd0sVSXqos7zNI1FNR3++p/+8/iHRsC733zbqUan/RuNTvfOZrtzImw0lj3PF0JKfqmuSiqyjJJoRtF0SsPL/UvD/vCh/nD4lx/75urn/ujt954MvPBNYbPxk14Q3hGG4XHXd8l1HFJSkVKC5+GfPCEZ4bOUsiii2aBPo/4WEbhpzC9QMNcj13NJef6IpHLBVUMTVhRFledZnMXpII5mTxXx7IGNtWf+6r2fPbP+fybgt153w9GFI4e/snDk2Mm5hQVqdVrkez65rkPC/oOujLYKEJFnlCUJJUzEFu7Ql+cWl2/2m+2e53vk4D3HARSEdwQI0DNIgsg8ihpzUc2aL0DoFHNMNtaodfgILV5zPakwpBqkFRVsDyTVGpXgsSpKvgYroNl0BtIGtLmy2l9fXXvrB77w+L/tRYD8QRc73e7v9pYPn1w6fIiWlxapt7hA84cXqbvco+7hBeoewvkyoO8t9WhxcZGWjxym5aOH6CW33ko33f6Ke46dOokplnCvh/ct8P485uoCc3NtoEudTpPaILjTwthqUMMHUUVGR06epFO33Ead3hwsoE3hfIPCXhPvdqi71MN3mOfvMn9okRbm56i30AMWaAFz4//qLcw1P/2ue65f2osAZ/eF337DjUcanbm3zuuJ5rvUXpynsN0g6SqS0mgfA9XEP6AJ6K6EKY7G5EvCcx4JpUhA48LDsYvnlSSlHP0+II0NFQWJJKOyLPF+RQQtykKbdE6yzmmuN0+Bfg9uU4c+lUpwjLAmi3cwVHg3A4SgNFfkYIQPwX18IqG6jizvJKJ/vCoC/GbrtZ35bqfdaVOz1aIQWvFCF8IrYncVAsNO01F8licxuaoFU9dfOCDyrKCCGESaCJzX5oKoFAYJwiCYyKnEfSU4EpLUDpZlMO+MnMolNwVZjqIKZOMBJgIvYcQ5rpWOviypkhAIpCiQqSq4Ry3aV20BJNVrWjDHwPfJD4FAa1SSIyULvztw8ElRkScUyYYP4RtUu7X9osbT7Ws24AFFBRREqtbH7MclCEynE2BE48ubFI8G1Lg0T34DpPo+KU2sJqasOABDeLacojAxoYAlxUlKQ1ji5eGYZpMxbQxna1dNgOs5t3haeN/VwYuFl+IKwgPa/CSEkIFPBAKEMq5RWe3LZx+0b2clkBqz1wLlOQewZDik4dpFWj93lqIoQrw5TH6nC/frkucHpFyP3cqmS6DSVsIukycR5oA71RMSMkJWimmjP7nwN4+sP3K1BEjPdU8ox2GTZ3+VrLQr5ks2WRfa8Vybzurd0dUKbzWfJhw3WHwd9UFGOurT4NIFunzpIh2/9WV07MaXUtjtEul5K5AkKvM+m3xtwCTYEdovYQlZntGxaURHV1Zo+cmzvdbSuZ99/wOPfIyZ3icBDlJdTykrvAL2qpVqQNZW+Csk2kqYL50kLFAtrOlb7c36l2m4sUonb7+Djt3yUnadzJV4rqTKqe209bYbAbLmI0N4Lnk+nLOVBO0OMs5y69hw9OF3v/GGL//B5554Yr8EKCGEx9HaBjwJ7MyZ1RWJ2ON6mrGmuNortP9q7YMAmHs8HpEXNKn3omsoi2KS7SYE12ECz1fbU4hdvNr4QtJz+CE5KUmqkuOFghuHYSALIX+eiP5w3y4gpHKt0DbS4iEprCw/WNHVFSqqbb8vSBS5IU+bNISvC11EwYfhEmkcceyocE3qFJoXLJSL47reNb+wwzashVWcZZSSNmgTKWN4p64mBggFBrbTXbWL+d0kWC38b3VmWXPQw0zG92EFpIWHv5YQvsgwFjlQUBpNjZFLhxwQJVyXU6WQlgQ7H0k7udUELIsJ5ciCsU5jKmZTk1nizL0qAmpRsdoNdku3+3Q7xVF9Je1nRnAbrKBmjtxlzjBaB+ejwRZdfvosNbpzVFYV+3bFgpU4L0ngWqGfx1hzyOEfJiaWBWeFMi8pShKaTqZ0eTSlrdGMBtN4xRYr5d4EMJu1rTMEk8Dg4+8jYjunS6mpA2gHafoeTiCkIGv6NYTJCxas0gRkKc4zfjRNUzrz0IO0dPQok+CHIac+Yl2UfFwLAXD0Z1JwQim0XMQxVTjPMecsSmgcZyz8xY1xem6Q/svVEYAEjUJD2UJDMwHs0rDYgTg1BAS+eUjsCAyJ1T4ZLZEWns3fpL8c2srg/zFqgEa7TTfecy8tIhCiGjWxQEijAPthzVjUpg7nRRGItctozAmLm42nNNzcorPfveieeGb19246MvfLH/nq+e/si4AK1MLMXPYrgDQc11rCDpuvjZB1lnOmqKUi8jGdsBYDcxSlCXwwX05/qPu5vK3y7FnhZ6MR5Zj7ZW98M3UOH6ZaW41OgUoZKxTbZiV2kCAAKmueGwEW5w5Jx6NKpeRDrACKO1xUMsvLe5I0/ygR3b0vAkpEJGgtYLYroKzsDUCQIcQyIHCcw5+V65LSBY5qEIffUhMAQc3ihctVsGnLWBMACx2gEKgmWPMvnbqeOotLVKQgs9WgyoPwLO224Rk7kjb+7TBC/UDhkUpArMjJ5bggKID1+q0IltUhP9i6c9+lcF4UGSIya8tEVViCXozYwEQsDCvG5nSwLyVJYQIeyQAEFEBp+apMgILgVDEJ7AJcwuoUiHfQdDE6VpIIwiMMmYLp++Ir5trlhUoIXijVeuWZ56aCxbnC6OCa4wOOo/ZNQJblY6SmBY7A2nTz3JSgSrFQbBmWZdLCZAkIUFTq8lkLnSTWR3HbrtZqgKO5jtY2ABYZp0AOiDmOq9q4ichKUoFj6v0r5B4u0sx1tgBZVqa40nEDJAv9rkbFLmziD6gFsr0JSLMNBJJTiNbaHWzwsX5sDN/kXXaLXPsy+54qXaq1Jdh7JLSfCuMGTAIBIMzOQzwKrjfGCFg1yAA95EyJVO6TcB0TBIXAaKQWZEivrTtRweSamqI2MasogATkxjPuLiXTCSVRrLl090NAPY2SSwkmyLlIybnlpZSywpscjOzAkbcG63ka6z4dzC0gqXBdqe2GRV0xERVgj5kMzuWC3YbT3dqF87R29kk6dPI6woxmuTuFZcQJJeMhpdMp9xsKmzZzCGnLaqDkeTAnZ5g0SSmF8qZZQTEwGEeoCaL7bc1GexIwS7OnosmE4tlMWwPnVhDApSrYBkqTyvSY5pRMZty4VEHIz5AQNlCxV7OmTfyypTUGs9jCnBgd14cACf3nFz5Px1/8Elo6cY2uD7gpmiBICszjNtok4WKu6yGwtQndGt152o49Spp0m2ZcVo/GE8ouXKTzF5+mx1ZGn7j/ic337TcGVBuD6OHJaEzj4YCauhvkufwlSqWjO2vP1vApzCyiCBqqSJAbNokEBMIxmWraRHJr5hbcGiulJIV5Pc+jIvDhai2KphE9+egj9Og3vkY3vuzldO3LX0HNhSXyGk1yPZDrgDybGiqOLfpYjzUHWKOYkqvFEMoLuj3yOvOUO98+9g+PbmZXKoTU7vMkzrJr5oNf8B3Vch3uA5qJU+78cuqKwHCE/D3u9xlIc+wGrBGlTPoSZLRPgo+FJY80mWX9bECtbLCCJrlKPHXTzXT7T/0MNXpL5DZb3GSpXMkolaDKgbY56ksiV4+gXAG11WAtqahrzi5RlFKWRNc1ZPWlx9bG39a397KA8vwkG64OJvc1w61fg+yUQdPtTocC3+MHkCU5yCRgOZ5OmIxWN8FM0GZVs5BBo41TxYTAeli4gstlBTi454JUEAZTd12XSpCHuMJdqKOnrgMxxFoVXggB8S5nJJsPbU+S6u3lsHIl3ndNyqacLaUSii1Tc73UCa4honw/LlAC+eefuPzx0HPugP/fEU1nZHqEHkdj7rwkKelAGccxzcByvdEfvbikblaZ8r8NIsJmi/cRpCO1DRgfBjkFl48uSe0CmLMuG2wJeZmT67haWJ5f4J6MEw7eJQvKXWGGLUZtY4QMQWnKLbI0K3h9kEYxxdGUvye+8747QjWQbkX58DOPrP3mT1zfe8fSJHpdO/APea5ypCQ23wzVUpRmg0Gc/felUfrQuc34az+dVG+5vax+saxqdpkKY7PTIo+gbU5nFYGRZxssHsigEqgxFLAaEJsEEU3QHWotjUmkISldGUYe53dybEoEMLLwhc4WJQc/01sscsrilCbjMQ22NvVuFY6n1I/iR/dJACMFZoO46H/60Y0PdX3nr0/OeS9qBt5c4FAjLep0lOSXLw3T1UFaTq1f0Ye+/PSH3lmL8Laq+jlezrLWgFaTzVxKbnablMpFkyIJjTt+QG5ecE8ghOtsoS/oIKA2EACJ9xhcE1SVxKitid3KxBlGwVZZ5AULn0Dr48GANtc2aH11XS+LH7z/v9bPbDe09iYgB6b2Ho3Soji9XoyJIrndC2GUQMGjneuDD55737sktWoSr4emONUpQDSFbjaaDZOi4lFKkOC63PjwG2ZTNM1guqMJPf7wf2DX5yg1ez0STqAFBxS7kd2XYFSVeS/POStxXJohhQ8xR78/qNZGswfu+9bKeyKict8WYDGzYwE0AA9QOwio7L1sR3DxgdYnHjr3+7/kqDY0/WreD/RMbS50inRMnxxXuGBSnscTqroi5YekVMCt+OE0GfzdP331d+bbjd51x5dumWuFNznSOSKVbEhBrpRC2M3UOsvLssw1CUk8TbLhNE4vrg2Tbz66Pv7KU5vxeavMHKj2T8A2CamdwL0CAfkOCwiBYoKrf/vwxfe83XM/6Pve9a4PoZTD6VEKbc62oyvNfkOtXBBR8opSwCVqvia7j69Nn1w9O5zSt1b+lYhkr+mEncALWr4bONp82ALKKk5QuAuqJtM86qdFvMM6c2BmEe+9O7w3xD56wC1gHpi74/j8rW959amPXHvqVPPQ8WM0v9CjBjKDo62Bl8k17ypXtpZPZxENtzZo5cIzdOHiKn396c33fubM5n12XmUhLGhXa7K2qHa4ZmKVNwZme7vA3qj38czUEiW/8czgsRvOtz7RCpu/GjQaHAh5w0UEJJXktYKQkslQymHtCwUIU7LPhe5tOrZawRzGbhKuLHxqCYiBbM+m6A8ZU0Bp3H9m9ZPHF9pvajbDa4PAN2U1/oWBz1mBKhAgTW5XUnJFR8pEfFeK41Z7KSDtnHIPAnaQANjP801ADUwApx8X7umLW3+OYPb+RhNW4PtsCXADJgMskLIlc223vqQgJsdzZfMVcKaHB5TQc/iRz9G8JZMAPPDYxhcurPW/2L88oOlwSHGU6KYLXMAk8qqy7W+zWcKqdc1udLk6MBnmhUgA7cggsy+d3fzjrX5/OhqMKJqNeTc41bkbQpcY6yylIom4vaaI2EpC1z1+z80LN7+ACWBEwPSRlclTT1wafnQymfDWdZqmtlFqzL9kVQiuAVzfI9/zKAzdVrvlv/OFTkBB1gr+/vTFT24ORqfjJOW2mKjJVINhg9f8jXaXmt0etbrz1Gy3qOH71HCd17/ttkPNFzABjBiYRDmNHr80/Hie6S5TQZWUnPq8ICC/1aFwDsIvLVJ7aYnaKIGbCJqh5x7FI7e80AmobSEylcKZZXluG6OC052EhMoFoHGv2ebfCewsgIT5eWo1AiEk6oHn8OPQ8/PJgFnoSYnq1UR+ZkaYwkcJTn2KTJM07M6BAF05bpKnxjccAAIYiSNLYZvrtL1exsCngpRd8Tm+S34TcaHV1DXDsRe2C2yjVLUUZh1/BU8xfJAUilzPIy/wSTlqjojUQSCgFrJmwm1Xb4cV2HNmwLqF7SC7Snmak4PgAlRXomIhJYBRADUfMRE7F+zmngCsog6CBYhK1Lnp6e/yA2nl48uC+/5laX6ZoqhrXmEeBAJISFFyFrA9bh6tdLw/oAWvza/OZFnGFWNelCsHhoAir2JugDAJxgIw2J1gs79XcFvb7DskcUSTKDnDbB2EIJgW6Jhlac2/7JQXTATZ5ibAFWIap/wHGJPRiEajWXxua/rwQSGABtN0axZDvxG0m8S8AZLGsdE4rs3GYxoP+jTAdvkAPf2N4fTBr5wfX9AcHQgLeHxltDaZTsfjwZD/smM8HAIjmgwnNMZ5f3ODtlbXaBPY2OwX314Z/cXOxutzAUHP72fhV+4++dkTR5buWj60zH/dEaLak0Lwvv4EhGxubtL6+iZ9Z2X4J586vfpnRLQBjA5EHQCUl8fxv4fe4K4iL+DrEwqCgOugOLa/4DiclE+vTz78qTNrH7cryRSgA0PAg2f7n7pX0ivjJLujPxp1XMfl+jjJi9Fwlp1+YmN231e/O/j6jp5+SgfoEwAngJcDdwM/Dtxrx9cCrwFeCfwYcAjwADpIFpABkSVCAO7urXl7f2z9PqMD+AmAZeAk8GLgJXa8FjgO9K6g+QORBXZanrdrmVsBuUX9fBHwP6w5oUlUPapLAAAAAElFTkSuQmCC\" title=\"emoji-thumbsdown\"></p>\n<blockquote>\n<p>“The road to Hell is paved with good intentions.” - Disputed Authorship</p>\n</blockquote>\n<h2 id=\"Gatsby-to-the-Rescue--My-New-Site\"><a href=\"#Gatsby-to-the-Rescue--My-New-Site\" aria-label=\"Gatsby to the Rescue  My New Site permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gatsby to the Rescue! – My New Site</h2>\n<p>Once taking a full-time position, especially when you have a family full of children, time is of premium value. I just never had a need or desire to update my portfolio online. I figured if recruiters wanted to head-hunt me from my current job, they need to come with a good monetary offer, good benefits and companies will have to go off content I have produced. <strong>So Why Update My Site Now?</strong> <em>Am I looking for new work?</em> Yes, and No. </p>\n<p>I’m not actively seeking new employment, but I am looking for solutions for upcoming projects at work, but more importantly, I’m looking to give my side-business a boost by offering niche services. There is a market for helping small businesses get a site up and running on <code class=\"language-text\">Wordpress</code>, <code class=\"language-text\">Squarespace</code>, even <code class=\"language-text\">Wix</code>, but **I want to produce sites I like to build as well as sites optimized for the web of the future - speedy, SEO optimized, accessible, and PWA friendly. </p>\n<p>I started seeing devs I know tweeting about <code class=\"language-text\">Gatsby</code> so I checked it out and fell immediately in love. I have downloaded and configured a dozen or so starters, and I have started making open-source contributions to the <a href=\"https://github.com/gatsbyjs/gatsby\">Gatsby repo on Github</a>, but it is time to put something into prod, and refactoring my portfolio and adding a blog seemed like the perfect first candidate. <a href=\"https://twitter.com/WesleyLHandy\">Hit me up on twitter with feedback on the new site</a></p>\n<h2 id=\"My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\"><a href=\"#My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\" aria-label=\"My Plan For This Blog  Or Why You Should Come Back permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>My Plan For This Blog – Or Why You Should Come Back</h2>\n<p>After this introductory post, I plan to post on the following:</p>\n<ul>\n<li>Technical Post on How I Built This Site</li>\n<li>Series of Technical Posts on Coding Practices I&#x26;rsquove Learned During My First Two Years of Professional Development</li>\n<li>Series of Posts Giving Specific Details and Advice Concerning Transitioning Careers, or On Becoming a 2nd Career Dev</li>\n<li>Other Technical Posts as topics arise</li>\n</ul>","id":"698dced9-6847-5220-ab59-f3e554d5a4ff","timeToRead":2,"frontmatter":{"date":"2019-04-04","path":"/blog/hello-world.html","tags":["gatsby","intro","development"],"title":"My New Blog - What To Expect from Me?","featuredAlt":"Batman says code like a champion today","redirect_from":null}}],"UX":[{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}}],"hooks":[{"excerpt":"I recently created my second production Gatsby application that gives a simple presentation of a local government open data dataset. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHYU7EBg//EABoQAQACAwEAAAAAAAAAAAAAAAECEQAQE0L/2gAIAQEAAQUClMJdTBs9Ua//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAEQIgITGR/9oACAEBAAY/Alk1Lg6f/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERIRBRYYHh/9oACAEBAAE/IbouiF6EgZZ3Im1Rwaf/2gAMAwEAAgADAAAAEOfP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAbEAEBAQACAwAAAAAAAAAAAAABEQAhMWGRof/aAAgBAQABPxBEigNVPmj7jxgjAAsEfWtAWznBdEwAQON//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"List of items waiting to be updated on scroll\"\n        title=\"List of items waiting to be updated on scroll\"\n        src=\"/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg\"\n        srcset=\"/static/310b5d4fba2ad789399bfaeb5397a733/afcd2/infinite-scroll.jpg 300w,\n/static/310b5d4fba2ad789399bfaeb5397a733/82472/infinite-scroll.jpg 600w,\n/static/310b5d4fba2ad789399bfaeb5397a733/c35de/infinite-scroll.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I recently created my second production <a href=\"https://gatsbyjs.org\">Gatsby</a> application that gives a <a href=\"https://vb-business-licenses.netlify.com\">simple presentation of a local government open data dataset</a>. I say production, though, much of the application is a proof-of-concept for a bigger application I have in the works (perhaps a startup in the mix? Not sure yet...). My app includes over 2400 nodes, so I needed a way to present the data in user-friendly ways. Each record in my collection included a set of categories, so I could easily create a categories page and split the data that way. However, I also want to eventually add search and also allow for a user to browse through the entire dataset. This is where I looked into <code class=\"language-text\">pagination</code> and <code class=\"language-text\">infinite-scroll</code>. You can <a href=\"https://www.gatsbyjs.org/docs/adding-pagination/\">read about adding pagination on the Gatsby blog</a>—it’s pretty straight-forward. Below is how I set up infinite-scroll that works in both development and production environments, as well as both in the browser and on touch screens. I was able to accomplish this using React <code class=\"language-text\">Hooks</code> within a functional component rather than a class-based component.</p>\n<h2 id=\"Infinite-Scroll--React-Hooks\"><a href=\"#Infinite-Scroll--React-Hooks\" aria-label=\"Infinite Scroll  React Hooks permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infinite Scroll &#x26; React Hooks</h2>\n<p>As much as this post is about integrating this within Gatsby, this is properly a <code class=\"language-text\">react</code> question. Gatsby is simply a platform for sourcing data. This could easily be implemented via <code class=\"language-text\">fetch</code>-ing of data from an API during client-side component. Adjust this method to what you need in your case.</p>\n<h3 id=\"Setting-Up-gatsby-nodejs\"><a href=\"#Setting-Up-gatsby-nodejs\" aria-label=\"Setting Up gatsby nodejs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up <code class=\"language-text\">gatsby-node.js</code></h3>\n<p>Within <code class=\"language-text\">gatsby-node.js</code> you will define an export named <code class=\"language-text\">createPages</code> that queries <code class=\"language-text\">graphql</code> for nodes from your data source and returns that list of nodes. Before returning, you can call the <code class=\"language-text\">createPage</code> API as many times a you need to generate your site. I intend, among many other things, to create a single page that generates and infinite scroll through my list of businesses. I will call <code class=\"language-text\">createPage</code>, passing to it the path of the page, the template for the page, and data that will be provided to the client via the <code class=\"language-text\">Context</code> api:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createPages</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> actions<span class=\"token punctuation\">,</span> graphql <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createPage <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> actions\n  <span class=\"token keyword\">return</span> <span class=\"token function\">graphql</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    {\n      #some query specific to your source data\n      specificNameOfYourQuery {\n        edges {\n          node {\n            #specific fields\n          }\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">reject</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>specificNameOfYourQuery<span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span> edges <span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> result<span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> infiniteScrollTemplate <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src/templates/infinite-scroll-template.js</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      path<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/businesses\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      component<span class=\"token punctuation\">:</span> infiniteScrollTemplate<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      context<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        edges<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">return</span> edges<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Creating-the-Template-that-Will-Include-Infinite-Scroll\"><a href=\"#Creating-the-Template-that-Will-Include-Infinite-Scroll\" aria-label=\"Creating the Template that Will Include Infinite Scroll permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating the Template that Will Include Infinite Scroll</h3>\n<p>From the root of your project, go into your <code class=\"language-text\">src</code> directory, create a <code class=\"language-text\">templates</code> folder if it doesn’t already exist, then create your template page. I entitled mine <code class=\"language-text\">infinite-scroll-template.js</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> src\n<span class=\"token function\">mkdir</span> templates\n<span class=\"token builtin class-name\">cd</span> templates\n<span class=\"token function\">touch</span> infinite-scroll-template.js</code></pre></div>\n<h4 id=\"React-Hooks---useEffect-and-useState\"><a href=\"#React-Hooks---useEffect-and-useState\" aria-label=\"React Hooks   useEffect and useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React Hooks - <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code></h4>\n<p>Once you have opened your template file within your IDE, you will need to import <code class=\"language-text\">React</code> as well as the <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> hooks. For Gatsby projects, you will also import your <code class=\"language-text\">Layout</code> component so that your page will match the rest of your site. The <code class=\"language-text\">createPage</code> API passes to your component <code class=\"language-text\">pageContext</code> as props where you can access the list of <code class=\"language-text\">edges</code> you pass to your template from <code class=\"language-text\">gatsby-node</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>We will focus on adding the core logic for infinite scroll to the <code class=\"language-text\">InfiniteScroll</code> functional component. We do not need to declare a <code class=\"language-text\">React</code> class because of the two aforementioned hooks—<code class=\"language-text\">useState</code> and <code class=\"language-text\">useEffect</code></p>\n<h5 id=\"Creating-and-Setting-Internal-State-with-useState\"><a href=\"#Creating-and-Setting-Internal-State-with-useState\" aria-label=\"Creating and Setting Internal State with useState permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating and Setting Internal State with <code class=\"language-text\">useState</code></h5>\n<p>React hooks allow us to write functional components that can “hook into” other React features. <code class=\"language-text\">useState</code> allows us to add state that is preserved between renders of a functional component. Unlike <code class=\"language-text\">state</code> within a React <code class=\"language-text\">class</code>, <code class=\"language-text\">useState</code> replaces the previous state rather than merging with previous state. Calling <code class=\"language-text\">useState</code> takes only one argument, whatever you conceive of as the initial state. The <code class=\"language-text\">useState</code> hook can be called multiple times, so rather than having a single <code class=\"language-text\">state</code> object, you can have multiple <code class=\"language-text\">state</code>-like variables. This is because the call to <code class=\"language-text\">useState</code> returns an array of two properties - the value of the current state and a function to call to update the value of that state.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>currentState<span class=\"token punctuation\">,</span> setState<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* some value or fn that returns a value */</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>For infinite scroll to work in this example, we need two state variables—a <code class=\"language-text\">boolean</code> indicating if there are more records to load and an <code class=\"language-text\">array</code> of the records already loaded. Seed the <code class=\"language-text\">currentList</code> with the first 10 records. Don’t worry if there is the possibility that the initial set is less than 10, <code class=\"language-text\">Array.slice</code> will return all records up to the length of the array if you provide an ending value greater than the last index of the array.</p>\n<p><em>Note: if we had a situation where you loaded data asynchronously from an API, we would also need someway to determine if data was in loading state</em></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// and if loading from an API asycrhonously</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> isLoading<span class=\"token punctuation\">,</span> setLoading <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<h5 id=\"Creating-Event-Handlers-to-Read-and-Set-State\"><a href=\"#Creating-Event-Handlers-to-Read-and-Set-State\" aria-label=\"Creating Event Handlers to Read and Set State permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Event Handlers to Read and Set State</h5>\n<p>Reading and setting state will occur within an event listener on the scroll position of the page. If you use an external api and that api is still loading content, we will return immediately, and we will also exit if we know there are no more edges to load. Otherwise, we will check to see if the scroll position of the <code class=\"language-text\">document</code> plus the <code class=\"language-text\">innerHeight</code> of the window equals the <code class=\"language-text\">offsetHeight</code> of the document, and if so, we can load more edges. Basically, this checks to see if the page is scrolled all the way to the bottom.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The <code class=\"language-text\">loadEdges</code> function will do the following, in order:</p>\n<ol>\n<li>if using an asynchronously api call, will set the loading flag to true</li>\n<li>determine if any more edges remaining</li>\n<li>slice a new chunk of edges and append to the current list</li>\n<li>if using an asynchronously api call, will return the loading flag to false</li>\n</ol>\n<p>Since I’m loading from the <code class=\"language-text\">Context</code> API, I will ignore steps 1 &#x26; 2 above.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n  <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n  <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n  <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><em>How would <code class=\"language-text\">isLoading</code> be used?</em></p>\n<p>Here is one overly simplistic example:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> newEdges <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://path/to/some/api'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> newEdges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n      <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n      <span class=\"token function\">addBusinesses</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>fetchNewEdgesError<span class=\"token punctuation\">:</span> err<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h5 id=\"Checking-The-Scroll-Position-on-Each-Render-with-useEffect\"><a href=\"#Checking-The-Scroll-Position-on-Each-Render-with-useEffect\" aria-label=\"Checking The Scroll Position on Each Render with useEffect permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Checking The Scroll Position on Each Render with <code class=\"language-text\">useEffect</code></h5>\n<p>The final step to initializing infinite scroll is the <code class=\"language-text\">useEffect</code> hook. The hook <code class=\"language-text\">useEffect</code> takes two arguments: a function, and an array. The first argument is the function that will be called every time <em>after</em> the component is rendered. This function is allowed to return another function which will be remembered and gets called as a cleanup function (I’m not sure I fully understand cleanups yet, but I think <a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">Dan Abramov does</a>). The second argument is an array of dependencies that would prevent an effect from being called if the values of those dependencies are unchanged between renders. Infinite scroll will a function with a cleanup callback as well as the array full of dependencies to work.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* function that gets called every time */</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* cleanup function to be called */</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token comment\">/* dependencies */</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">useEffect</code> is a great place to initialize event listeners on the <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code>, as well as to remove those listeners during cleanup, such as listening for <code class=\"language-text\">scroll</code> events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>And thus, the cleanup function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This gives us an almost complete <code class=\"language-text\">useEffect</code> function call, we will simply add our state variables to the dependencies array so that effect is only set or cleaned up when the variables change:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>With state, event handlers, effects initialized, we are free to return the <code class=\"language-text\">jsx</code> for the scrolling list. The following maps over the <code class=\"language-text\">currentList</code> array. It also adds labels displaying the current state of the list:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span> \n                <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                fields \n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      hasMore <span class=\"token operator\">&amp;&amp;</span>\n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* if using this flag, otherwise omit */</span>\n      isLoading <span class=\"token operator\">&amp;&amp;</span> \n        <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"Putting-It-All-Together\"><a href=\"#Putting-It-All-Together\" aria-label=\"Putting It All Together permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Putting It All Together</h3>\n<p>Now we have a complete picture of the infinite scroll functional component. See below, but don’t leave yet, we still have to account for <code class=\"language-text\">gatsby build</code> and mobile events.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> Layout <span class=\"token keyword\">from</span> <span class=\"token string\">'../components/Layout'</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScroll</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> pageContext<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> edges <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> hasMore<span class=\"token punctuation\">,</span> setMore <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>edges<span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span> currentList<span class=\"token punctuation\">,</span> addToList <span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">loadEdges</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentLength <span class=\"token operator\">=</span> currentList<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> more <span class=\"token operator\">=</span> currentLength <span class=\"token operator\">&lt;</span> edges<span class=\"token punctuation\">.</span>length\n    <span class=\"token keyword\">const</span> nextEdges <span class=\"token operator\">=</span> more <span class=\"token operator\">?</span> edges<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span>currentLength<span class=\"token punctuation\">,</span> currentLength <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token function\">setMore</span><span class=\"token punctuation\">(</span>more<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">addToList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>currentList<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>nextEdges<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* shorthand for React.Fragment */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>\n          currentList<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> fields <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fields-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>idx<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> index<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n                <span class=\"token punctuation\">{</span> \n                  <span class=\"token comment\">/* you will know the specifics here from how you load your data */</span>\n                  fields \n                <span class=\"token punctuation\">}</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n           <span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>All Businesses Loaded<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n        hasMore <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Scroll Down to Load More<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfiniteScrollTemplate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Layout <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>InfiniteScroll <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>props<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> InfiniteScrollTemplate</code></pre></div>\n<p>This functional component will work just fine during development on a desktop browser. But you will lose the scroll effect during the build and on touch screens. It will fail during build because client globals like <code class=\"language-text\">window</code> and <code class=\"language-text\">document</code> are undefined during the build. It will fail on mobile because <code class=\"language-text\">scroll</code> is a mouse event. We need to add some conditions for our event listeners to handle both conditions.</p>\n<h3 id=\"Optimizing-for-Production-and-Touch-Screens\"><a href=\"#Optimizing-for-Production-and-Touch-Screens\" aria-label=\"Optimizing for Production and Touch Screens permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing for Production and Touch Screens</h3>\n<p>In addition to adding an event listener on <code class=\"language-text\">scroll</code>, we also need event listeners for <code class=\"language-text\">touchend</code> and <code class=\"language-text\">resize</code> (to handle situations where someone resizes their browser), plus we need to add <code class=\"language-text\">preventDefault</code> to touch events to prevent duplicate events being fired in certain situations where devices have both a mouse and a touch screen. First, create a new event handler for handling <code class=\"language-text\">touchend</code>. This new handler will simply prevent the default actions on <code class=\"language-text\">touchend</code> and call the handler for the scroll event (which simply checks to see if we should load more documents). Second, update the <code class=\"language-text\">useEffect</code> function to add the additional event handlers. </p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleTouchEnd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">handleScroll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Finally, we need to add a few simple <code class=\"language-text\">boolean</code> checks (<code class=\"language-text\">window &amp;&amp;</code>) to every instance of <code class=\"language-text\">window</code> or <code class=\"language-text\">document</code> so that the build process succeeds <em>and</em> so that infinite scroll still operates in the client. Plus, we need to change the scroll position check to be <code class=\"language-text\">&gt;=</code> instead of the strict equality <code class=\"language-text\">===</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleScroll</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span>hasMore <span class=\"token operator\">||</span> isLoading <span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> window <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">     <span class=\"token punctuation\">(</span> window<span class=\"token punctuation\">.</span>innerHeight <span class=\"token operator\">+</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>scrollTop <span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>offsetHeight <span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span></span>    <span class=\"token function\">loadEdges</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'scroll'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'resize'</span><span class=\"token punctuation\">,</span> handleScroll<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    window <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> handleTouchEnd<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>hasMore<span class=\"token punctuation\">,</span> currentList<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>There you have it! You have a component that will implement infinite scroll in the browser, on touch screens, and in production within a Gatsby or React application. </p>\n<p>Check out the following page in your browser and on mobile to <a href=\"https://vb-business-licenses.netlify.com/businesses\">see this code in action</a>. </p>\n<p>You can also see <a href=\"https://github.com/wesleylhandy/got-business-client\">my specific implementation of the source code on github</a>.</p>\n<hr/>\n<p><strong><em>Update</em></strong></p>\n<p>I had to adjust the <code class=\"language-text\">touchend</code> handler to account for and exclude touches on links. See <a href=\"/blog/improving-touch-events-upon-infinite-scrolling-component.html\">my next blog post on this topic</a>.</p>","id":"7fcb149e-c917-5351-99be-8c78d8765d8b","timeToRead":11,"frontmatter":{"date":"2019-05-20","path":"/blog/infinite-scroll-mobile-desktop-gatsby.html","tags":["gatsby","development","UX","react","hooks","infinite scroll"],"title":"Adding Infinite Scroll For Both Desktop and Mobile in Your Gatsby Project with React Hooks","featuredAlt":"List of items waiting to be updated on scroll","redirect_from":["/blog/inifinite-scroll-mobile-desktop-gatsby.html"]}}],"seo":[{"excerpt":"I was drawn to Gatsby out of my love for React, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as  was taking off. It was a challenge at first to…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.456286427976686%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABenOzxcwzP//EABcQAQEBAQAAAAAAAAAAAAAAAAABAgT/2gAIAQEAAQUC6JdNK20r/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAARECEiD/2gAIAQEABj8CFZJa/8QAGxAAAQQDAAAAAAAAAAAAAAAAAQARITEQQYH/2gAIAQEAAT8hf5dwCOJfqtnsv//aAAwDAQACAAMAAAAQOz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQIBAT8QVkz/xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhENH/2gAIAQEAAT8QkAKol+66ej2CJljY9c1tfD//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Gatsby loves to claim to produce the fastest sites around\"\n        title=\"Gatsby loves to claim to produce the fastest sites around\"\n        src=\"/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg\"\n        srcset=\"/static/d580489e8877a5a2439959d5d0b2b3cd/afcd2/gatsby-stickers.jpg 300w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/82472/gatsby-stickers.jpg 600w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/c35de/gatsby-stickers.jpg 1200w,\n/static/d580489e8877a5a2439959d5d0b2b3cd/de376/gatsby-stickers.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>I was drawn to <a href=\"https://www.gatsbyjs.org/\">Gatsby</a> out of my love for <a href=\"https://reactjs.org/\">React</a>, and my desire to serve fast, performant, responsive applications. I started learning React just as the library started embracing ES6 classes, and just as <code class=\"language-text\">create-react-app</code> was taking off. It was a challenge at first to learn the simplicity of proxying to get the front end to run concurrently with a <code class=\"language-text\">node</code> / <code class=\"language-text\">express</code> API. And yet, to get from that point to server-side rendering took a little more research and effort. It has been fun learning with and from the larger coding community. I could continue to enumerate the other technical issues I have encountered and solved, and yet some others I still have to learn, but note something important so far regarding my journey—it has been a <em>techinical-first-journey</em>, focused on knowledge and skill of the various langauges and libraries, necessary yes, but perhaps not primary. The last thing on mind has been <strong>SEO</strong>, <strong>accessbility</strong>, and <strong>security</strong>.</p>\n<h2 id=\"Setting-An-SEO-First-Mindset\"><a href=\"#Setting-An-SEO-First-Mindset\" aria-label=\"Setting An SEO First Mindset permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting An SEO-First Mindset</h2>\n<p>I’ll leave accessibility and then security future posts, but what has impressed me thus far in my dive into the <code class=\"language-text\">Gatbsy</code> ecosystem has been <strong>the ease to configure search engine optimization</strong>. In fact, you can create an architecture for your site or app that is SEO driven long before developing your UI. I want to walk you through the things I have learned so far in optimizing a Gatsby site for SEO right from the start.</p>\n<h3 id=\"Before-We-Begin\"><a href=\"#Before-We-Begin\" aria-label=\"Before We Begin permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><em>Before We Begin</em></h3>\n<p>You need to have some familiarity with Gatsby. To learn how to install the <code class=\"language-text\">gatbsy-cli</code> and create a new Gatsby project from one of the many Gatsby Starters, please consider <a href=\"https://www.gatsbyjs.org/tutorial/\">completing the Gatsby tutorial</a>.</p>\n<p>Otherwise, <a href=\"https://www.gatsbyjs.org/starters/?c=SEO&#x26;v=2\">pick a starter</a> from the SEO category, and open the SEO component or just use the <code class=\"language-text\">gatsby-starter-default</code> by running from the command line:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  gatsby new seo-blog https://github.com/gatsbyjs/gatsby-starter-default</code></pre></div>\n<p>The SEO component is dependent upon <code class=\"language-text\">react-helmet</code>, if your starter does not come with SEO initialized be sure to add it. We also want to add some other features like sitemap, google analytics, and RSS feed, for syndication. Finally, we need to create <code class=\"language-text\">robots.txt</code> to manage how search engines crawl the site. I’ve split up the commands below for spacing purposes, but they can all run as one <code class=\"language-text\">yarn add</code> command:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> react-helmet gatsby-plugin-react-helmet \n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-feed gatsby-plugin-google-analytics gatsby-plugin-sitemap\n  <span class=\"token function\">yarn</span> <span class=\"token function\">add</span> gatsby-plugin-robots-txt</code></pre></div>\n<p>With your starter and these plugins installed, we are ready to set up our site for SEO Performance.</p>\n<h3 id=\"Setting-up-gatsby-configjs\"><a href=\"#Setting-up-gatsby-configjs\" aria-label=\"Setting up gatsby configjs permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting up <code class=\"language-text\">gatsby-config.js</code></h3>\n<p>Within the root of your new Gatsby project sits the file Gatsby uses to configure  <code class=\"language-text\">siteMetaData</code> and <code class=\"language-text\">plugins</code> and <a href=\"https://www.gatsbyjs.org/docs/gatsby-config/\">several other important features</a>.</p>\n<p>This file, <code class=\"language-text\">gatsby-config.js</code> is going to do the heavy lifting of importing all your vital SEO related content into GraphQL or create necessary files directly (like <code class=\"language-text\">robots.txt</code>).</p>\n<h4 id=\"Site-Metadata\"><a href=\"#Site-Metadata\" aria-label=\"Site Metadata permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Site Metadata</h4>\n<p>Metadata is as it sounds, data that extends across or throughout the entirity of your site. It can be used anywhere, but will come most in handy when configuring your SEO component as well as Google Structured Data.</p>\n<p>Initialize your metadata as an Object literal with key/value pairs that can be converted into <code class=\"language-text\">&lt;meta&gt;</code> tags, or can be passed to sitemaps or footers, wherever you might need global site data: </p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\">  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>title<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation\">=</span><span class=\"token punctuation\">\"</span>My Super Awesome Site will blow your mind with radical content, extravagant colors, and hip designs.<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span></code></pre></div>\n<p>Here is where you need to plan what might use across your site:</p>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> title</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> description</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> keywords</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> site verification</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> social links</li>\n<li class=\"task-list-item\"><input type=\"checkbox\" disabled> other</li>\n</ul>\n<p>With <code class=\"language-text\">siteMetadata</code> set up, your can now query this data to be used within your plugin initialization, even within the same <code class=\"language-text\">gatsby-config.js</code> file. I’ve organized my <code class=\"language-text\">siteMetadata</code> so that I can make the following query:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n    site {\n      siteMetadata {\n        title\n        description\n        author\n        siteUrl\n        siteVerification {\n          google\n          bing\n        }\n        social {\n          twitter\n        }\n        socialLinks {\n          twitter\n          linkedin\n          facebook\n          stackOverflow\n          github\n          instagram\n          pinterest\n          youtube\n          email\n          phone\n          fax\n          address\n        }\n        keywords\n        organization {\n          name\n          url\n        }\n      }\n    }\n  </span><span class=\"token template-punctuation string\">`</span></span></code></pre></div>\n<p>This query returns an object matching this query structure:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  site<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      title<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      description<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      author<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteUrl<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n      siteVerification<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        google<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        bing<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      social<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      socialLinks<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        twitter<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        linkedin<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        facebook<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        stackOverflow<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        github<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        instagram<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        pinterest<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        youtube<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        email<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        phone<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        fax<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        address<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      keywords<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>String<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n      organization<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        name<span class=\"token punctuation\">:</span> String<span class=\"token punctuation\">,</span>\n        url<span class=\"token punctuation\">:</span> String\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h4 id=\"Plugin-Setup\"><a href=\"#Plugin-Setup\" aria-label=\"Plugin Setup permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Plugin Setup</h4>\n<p>We are going to focus on four plugins, each for the sitemap, RSS feed, robots.txt file, and Google Analytics (for tracking the SEO success of your site). We’ll initialize the plugins immediately following <code class=\"language-text\">siteMetaData</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    siteMetadata<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/** SEE ABOVE **/</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span> </span><span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">/** An ARRAY **/</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> </span>  <span class=\"token punctuation\">}</span></code></pre></div>\n<ol>\n<li><strong>gatsby-plugin-sitemap</strong></li>\n</ol>\n<p>The sitemap plugin can be used simply or with options. Generally, you want to include anything and everything with high quality content, and <strong><em>exclude duplicate content, thin content, or pages behind authentication</em></strong>. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/creating-a-sitemap/\">detailed walkthrough for setting up your sitemap</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  plugins<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-sitemap</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">          exclude<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/admin</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/tags/links</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">]</span></span>        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span></code></pre></div>\n<ol start=\"2\">\n<li><strong>gatsby-plugin-feed</strong></li>\n</ol>\n<p><strong><em>An RSS feed helps with syndication of content on your site, like if you had a blog and wanted to cross-post to another better established blog, and it helps communicate changes to your site to search engines.</em></strong> This plugin allows you to create any number of different feeds utlizing the power of GraphQL to query your data. Some of what is below is dependent on how you structure your pages and posts in <code class=\"language-text\">gatsby-node.js</code>. The feed will walk through each of your pages in <code class=\"language-text\">markdown</code> generate an XML RSS Feed. Gatsby provides a <a href=\"https://www.gatsbyjs.org/docs/adding-an-rss-feed/\">detailed walkthrough for adding an RSS feed</a>. </p>\n<p><strong><em>Note particularly the use of queries below to complete the feed.</em></strong></p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token comment\">// graphQL query to get siteMetadata</span></span><span class=\"gatsby-highlight-code-line\">      query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">        {</span><span class=\"gatsby-highlight-code-line\">          site {</span><span class=\"gatsby-highlight-code-line\">            siteMetadata {</span><span class=\"gatsby-highlight-code-line\">              title</span><span class=\"gatsby-highlight-code-line\">              description</span><span class=\"gatsby-highlight-code-line\">              siteUrl</span><span class=\"gatsby-highlight-code-line\">              site_url: siteUrl,</span><span class=\"gatsby-highlight-code-line\">              author</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">        }</span><span class=\"gatsby-highlight-code-line\">      </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>      feeds<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token comment\">// an array of feeds, I just have one below</span>\n        <span class=\"token punctuation\">{</span>\n          <span class=\"token function-variable function\">serialize</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> query<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> site<span class=\"token punctuation\">,</span> allMarkdownRemark <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> siteMetadata <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> siteUrl <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> site<span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">return</span> allMarkdownRemark<span class=\"token punctuation\">.</span>edges<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">edge</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n              <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> \n                node<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> \n                  frontmatter<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                    title<span class=\"token punctuation\">,</span> \n                    date<span class=\"token punctuation\">,</span> \n                    path<span class=\"token punctuation\">,</span> \n                    author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> name<span class=\"token punctuation\">,</span> email <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featured<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span> publicURL <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> \n                    featuredAlt\n                  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                  excerpt<span class=\"token punctuation\">,</span> \n                  html\n                <span class=\"token punctuation\">}</span> \n              <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> edge<span class=\"token punctuation\">;</span>\n              <span class=\"token keyword\">return</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">assign</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> edge<span class=\"token punctuation\">.</span>node<span class=\"token punctuation\">.</span>frontmatter<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n                language<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">en-us</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                title<span class=\"token punctuation\">,</span>\n                description<span class=\"token punctuation\">:</span> excerpt<span class=\"token punctuation\">,</span>\n                date<span class=\"token punctuation\">,</span>\n                url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                guid<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                author<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>email<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> ( </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>name<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> )</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n                image<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                  url<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> publicURL<span class=\"token punctuation\">,</span>\n                  title<span class=\"token punctuation\">:</span> featuredAlt<span class=\"token punctuation\">,</span>\n                  link<span class=\"token punctuation\">:</span> siteUrl <span class=\"token operator\">+</span> path<span class=\"token punctuation\">,</span>\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n                custom_elements<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> <span class=\"token string\">\"content:encoded\"</span><span class=\"token punctuation\">:</span> html <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n              <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token comment\">// query to get blog post data</span></span><span class=\"gatsby-highlight-code-line\">          query<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></span><span class=\"gatsby-highlight-code-line\">          {</span><span class=\"gatsby-highlight-code-line\">            allMarkdownRemark(</span><span class=\"gatsby-highlight-code-line\">              sort: { order: DESC, fields: [frontmatter___date] },</span><span class=\"gatsby-highlight-code-line\">            ) {</span><span class=\"gatsby-highlight-code-line\">              edges {</span><span class=\"gatsby-highlight-code-line\">                node {</span><span class=\"gatsby-highlight-code-line\">                  excerpt</span><span class=\"gatsby-highlight-code-line\">                  html</span><span class=\"gatsby-highlight-code-line\">                  frontmatter {</span><span class=\"gatsby-highlight-code-line\">                    path</span><span class=\"gatsby-highlight-code-line\">                    date</span><span class=\"gatsby-highlight-code-line\">                    title</span><span class=\"gatsby-highlight-code-line\">                    featured {</span><span class=\"gatsby-highlight-code-line\">                      publicURL</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                    featuredAlt</span><span class=\"gatsby-highlight-code-line\">                    author {</span><span class=\"gatsby-highlight-code-line\">                      name</span><span class=\"gatsby-highlight-code-line\">                      email</span><span class=\"gatsby-highlight-code-line\">                    }</span><span class=\"gatsby-highlight-code-line\">                  }</span><span class=\"gatsby-highlight-code-line\">                }</span><span class=\"gatsby-highlight-code-line\">              }</span><span class=\"gatsby-highlight-code-line\">            }</span><span class=\"gatsby-highlight-code-line\">          }</span><span class=\"gatsby-highlight-code-line\">          </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>          output<span class=\"token punctuation\">:</span> <span class=\"token string\">\"/rss.xml\"</span><span class=\"token punctuation\">,</span>\n          title<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">My Awesome Site | RSS Feed</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li><strong>gatsby-plugin-robots-txt</strong></li>\n</ol>\n<p>With <code class=\"language-text\">robots.txt</code> files, you can instruct crawlers to ignore your site and/or individual paths, based on certain conditions. <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-robots-txt/?=robots\">See the plugin description for more detailed use cases</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token string\">'gatsby-plugin-robots-txt'</span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      policy<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> userAgent<span class=\"token punctuation\">:</span> <span class=\"token string\">'*'</span><span class=\"token punctuation\">,</span> allow<span class=\"token punctuation\">:</span> <span class=\"token string\">'/'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span></span>    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"4\">\n<li><strong>gatsby-plugin-google-analytics</strong></li>\n</ol>\n<p>Google analytics will help you track how users find and interact with your site, so you can manage and update your site over time for better SEO results. Verify your site with Google and store your analytics key here:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">gatsby-plugin-google-analytics</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n    options<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      trackingId<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<h3 id=\"Optimizing-the-SEO-Component\"><a href=\"#Optimizing-the-SEO-Component\" aria-label=\"Optimizing the SEO Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Optimizing the SEO Component</h3>\n<p>The secret sauce behind the SEO Component is the well-known <code class=\"language-text\">react-hemlet</code> package. Every page and every template imports the SEO Component and thus you can pass specific information to adjust the metadata for each public facing page.</p>\n<p>Use your imagination—what can you pass to this component to create the perfect SEO enabled page? Is the page a landing page, a blog post, a media gallery, a video, a professional profile, a product? There are 614 types of schemas listed on <a href=\"https://schema.org/docs/schemas.html\">https://schema.org</a>. You can pass specific schema related information to the SEO component.</p>\n<p>If any of these values you pass to the component, a <code class=\"language-text\">StaticQuery</code> would fill in what’s missing with <code class=\"language-text\">siteMetaData</code>. From this data, <code class=\"language-text\">react-helmet</code> creates all the <code class=\"language-text\">&lt;meta&gt;</code> tags, including <code class=\"language-text\">open graph</code> and <code class=\"language-text\">twitter</code> card tags, and pass relevant data to another component that returns <code class=\"language-text\">Google Structured Data</code>.</p>\n<p>Rather than including a long code-snippet, refer back to the <a href=\"#Before-We-Begin\">Before We Begin</a> section, or <a href=\"https://www.gatsbyjs.org/packages/gatsby-plugin-react-helmet/\">refer to the <code class=\"language-text\">gatsby-plugin-react-helment</code> page for installation</a>. But please note, the structure of my SEO Component follows that outlined by <a href=\"https://blog.dustinschau.com/search-engine-optimization-with-gatsby\">this excellent post</a> by Dustin Schau.</p>\n<p>As I have tinkered with the SEO Component, here are the features I added:</p>\n<ol>\n<li>Additional Fields Passed to Component to:  distinguish between types of pages, such as blog posts, to handle authors of content other than main site author, and to handle changes in date modified for pages and posts. More could be added in the future.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    description<span class=\"token punctuation\">,</span>\n    lang<span class=\"token punctuation\">,</span>\n    meta<span class=\"token punctuation\">,</span>\n    keywords<span class=\"token punctuation\">,</span>\n    image<span class=\"token punctuation\">,</span>\n    title<span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// highlight start</span>\n    pathname<span class=\"token punctuation\">,</span>\n    isBlogPost<span class=\"token punctuation\">,</span>\n    author<span class=\"token punctuation\">,</span>\n    datePublished <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    dateModified <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span>\n    <span class=\"token comment\">// highlight-end</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></code></pre></div>\n<ol start=\"2\">\n<li>Setting <code class=\"language-text\">og:type</code> conditionally</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">{</span>\n    property<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">og:type</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> isBlogPost <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">article</span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">website</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </code></pre></div>\n<ol start=\"3\">\n<li>Always setting an <code class=\"language-text\">alt</code> property on the image object</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"gatsby-highlight-code-line\">  <span class=\"token comment\">// ALWAYS ADD IMAGE:ALT</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">    property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:alt\"</span><span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">    content<span class=\"token punctuation\">:</span> image<span class=\"token punctuation\">.</span>alt </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span></code></pre></div>\n<ol start=\"4\">\n<li>Handling Secure Images</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token comment\">// handle Secure Image</span></span><span class=\"gatsby-highlight-code-line\">    metaImage <span class=\"token operator\">&amp;&amp;</span> metaImage<span class=\"token punctuation\">.</span><span class=\"token function\">indexOf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"https\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token operator\">-</span><span class=\"token number\">1</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">?</span> <span class=\"token punctuation\">[</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">            property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"twitter:image:secure_url\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">            content<span class=\"token punctuation\">:</span> metaImage<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span> property<span class=\"token punctuation\">:</span> <span class=\"token string\">\"og:image:secure_url\"</span><span class=\"token punctuation\">,</span> content<span class=\"token punctuation\">:</span> metaImage <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token punctuation\">]</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span>  <span class=\"token punctuation\">)</span></code></pre></div>\n<ol start=\"5\">\n<li>Adding a Component to handle <code class=\"language-text\">Google Structured Data</code> using <a href=\"https://schema.org\">schema.org</a> categories. I came across an example of such a component from reading through various documentation and articles, I can’t recall where I saw the link first, but I borrowed and adapted <a href=\"https://github.com/jlengstorf/gatsby-theme-jason-blog/blob/e6d25ca927afdc75c759e611d4ba6ba086452bb8/src/components/SEO/SchemaOrg.js\">from Jason Lengstorf</a>. I made two small adaptations to his excellent work.</li>\n</ol>\n<h3 id=\"Configuring-the-SchemaOrg-Component\"><a href=\"#Configuring-the-SchemaOrg-Component\" aria-label=\"Configuring the SchemaOrg Component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Configuring the SchemaOrg Component</h3>\n<p>You will import and call the <code class=\"language-text\">SchemaOrg</code> Component from within the <code class=\"language-text\">SEO</code> Component and place it just after the closing tag of the <code class=\"language-text\">Helmet</code> Component and pass the following properties:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token keyword\">function</span> <span class=\"token constant\">SEO</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token operator\">...</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">...</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Fragment Shorthand */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">&lt;</span>Helmet \n          <span class=\"token punctuation\">{</span><span class=\"token comment\">/* All the Meta Tag Configuration */</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>SchemaOrg</span><span class=\"gatsby-highlight-code-line\">          isBlogPost<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          url<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          title<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          image<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaImage<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          description<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>metaDescription<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          datePublished<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>datePublished<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          dateModified<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>dateModified<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          canonicalUrl<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>siteUrl<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          author<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isBlogPost <span class=\"token operator\">?</span> author <span class=\"token punctuation\">:</span> siteMetadata<span class=\"token punctuation\">.</span>author<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          organization<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>organization<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          defaultTitle<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>I won’t copy and paste the entire <code class=\"language-text\">SchemaOrg</code> Component here. Grab it from the link above, and give Jason Lengstorf some credit in your code. Below are the few additions I made:</p>\n<ol>\n<li>I added author email to the Schema. This will come from <code class=\"language-text\">siteMetadata</code> for most pages and from post <code class=\"language-text\">frontmatter</code> from blog posts. This will support multiple authors for your site and each page can reflect that uniquely if you so choose.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  author<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Person\"</span><span class=\"token punctuation\">,</span>\n    name<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    email<span class=\"token punctuation\">:</span> author<span class=\"token punctuation\">.</span>email<span class=\"token punctuation\">,</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"2\">\n<li>I updated the organization logo from a simple URI to an <code class=\"language-text\">ImageObject</code> type. While the <code class=\"language-text\">String</code> URI is acceptable to the <code class=\"language-text\">Organization</code> type, Google has specific expectations and was throwing an error until I changed it to an <code class=\"language-text\">ImageObject</code>. </li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  publisher<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Organization\"</span><span class=\"token punctuation\">,</span>\n    url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    logo<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token string\">\"@type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"ImageObject\"</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      url<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      width<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>width<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      height<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>logo<span class=\"token punctuation\">.</span>height<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span>    name<span class=\"token punctuation\">:</span> organization<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<ol start=\"3\">\n<li>Add <code class=\"language-text\">dataModified</code> to reflect changes to the page after initial publication for the <code class=\"language-text\">BlogPosting</code> type.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">  datePublished<span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">  dateModified<span class=\"token punctuation\">,</span></span></code></pre></div>\n<p>When you have more complexity within you site, you can pass flags to this Component to return differing types of schema as needed. But no matter what you do, do not put your site into production without first passing through the <code class=\"language-text\">script</code> generated by the component to the <a href=\"https://search.google.com/structured-data/testing-tool/u/0/\">Google Structured Data Testing Tool</a>.</p>\n<h2 id=\"Concluding-Thoughts\"><a href=\"#Concluding-Thoughts\" aria-label=\"Concluding Thoughts permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Concluding Thoughts</h2>\n<p>When I configured my site according to the plan I outlined above, not only do I get image rich, descriptive Social Sharing cards, I get perfect SEO scores when running a Lighthouse Audit on my site:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 816px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 17.15686274509804%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAmUlEQVQI1z2N2w6CMBBE+f+/88H4YGJURAEpvdDL0lLGdo1OMtmzmexss+87qiYn8bYzc9wSWtVj3SLvs9eQxVUhEh5qwJq+mbQeiydmIkLzK7yMLZuPVsLhfoIj/89uU8fsY8CxO/PTqqsY0UnB7JxDU6GW2sWyq1JMUFKVGTkzxpRsQc4ZIQRorWHLM1OKxNBDPF/wpaxmH1t76BizOlMxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        title=\"Lighthouse Audit gives my website a 100% score for Search Engine Optimization\"\n        src=\"/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png\"\n        srcset=\"/static/384cdb474a81538eeda376637170d853/135ae/lighthouse_audit_seo.png 300w,\n/static/384cdb474a81538eeda376637170d853/34e8a/lighthouse_audit_seo.png 600w,\n/static/384cdb474a81538eeda376637170d853/ac127/lighthouse_audit_seo.png 816w\"\n        sizes=\"(max-width: 816px) 100vw, 816px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>You also see that I scored 100% for Accessibility on my site. This is so easy to score with Gatsby as well, and I’ll talk about what I learned on this topic in the future.</p>\n<p>Cross-Posted: <a href=\"https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g\">https://dev.to/wesleylhandy/putting-seo-first-with-gatsby-3n2g</a></p>","id":"fc7a6836-1cdc-519e-8c65-39beae2150c8","timeToRead":10,"frontmatter":{"date":"2019-04-20","path":"/blog/seo-accessibility-first-gatsby.html","tags":["gatsby","development","seo"],"title":"Putting SEO First with Gatsby","featuredAlt":"Gatsby loves to claim to produce the fastest sites around","redirect_from":null}}],"2ndCareerDev":[{"excerpt":"Changing careers is tough.  For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.539550374687764%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABSy6MV5lEf//EABwQAAIBBQEAAAAAAAAAAAAAAAECAAMREiEiM//aAAgBAQABBQINSnJawMX1bRyIn//EABURAQEAAAAAAAAAAAAAAAAAABEA/9oACAEDAQE/AVm//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BR//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhMTJS/9oACAEBAAY/AslKsGxBXLf/xAAcEAACAgIDAAAAAAAAAAAAAAAAARExIWGhseH/2gAIAQEAAT8hRw3nRKuZ7LEuBZVq8KCJSVScH//aAAwDAQACAAMAAAAQ99//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQMBAT8QSJMf/8QAFhEBAQEAAAAAAAAAAAAAAAAAABFR/9oACAECAQE/EIrX/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARITFRcYH/2gAIAQEAAT8QDKbViX7BgkAyl1W3yFrM6UcQjVscfZgKoItBvYZVbHA8T//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        title=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        src=\"/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg\"\n        srcset=\"/static/30874b6095537c9af16ed94f9b05bc86/afcd2/bootcamp-graduation.jpg 300w,\n/static/30874b6095537c9af16ed94f9b05bc86/82472/bootcamp-graduation.jpg 600w,\n/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg 1200w,\n/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>Changing careers is tough. </p>\n<p>For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees one obtains come higher-level and yet more narrow opportunities. Such opportunities fade into nothing if just can’t break-in your desired field. </p>\n<p>Over the past three years I have received several phone calls, emails, and direct messages asking me for advice, whether or not one of my friends or their loved ones should consider a career change like I did. </p>\n<p>There are a lot of very talented, highly educated people stuck in low-paying, dead-end jobs, or who just can’t break in to their dream field. </p>\n<p>I’m writing this post for them and for the many others out there like them. I want to answer some of the most commonly asked questions I have received. I want to be specific to my particular set of choices, recognizing that everybody’s situation is different. I also want to humbly admit that I’m writing from a Western, middle class perspective. Not everyone is afforded the types of opportunities from which I have derived great benefit. This may look different for someone in a developing country, and the sets of choices you have will lean away from formal programs that cost a lot of money. If this is you reading this post, I sympathize with you and want to be an encouragement to you in any way I can. Hit me up <a href=\"https://twitter.com/wesleylhandy\">on twitter</a> and ask me any questions you got. </p>\n<p>This is the first post in a series on my decision to switch careers, attend a bootcamp, and land my first dev job. This post will cover the first two questions in the list below:</p>\n<h2 id=\"Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\"><a href=\"#Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\" aria-label=\"Questions Ill Answer to Aid Your Decision Making Process Through This Series permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Questions I’ll Answer to Aid Your Decision Making Process Through This Series</h2>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\">Why Should I Consider a Career Switch Into Web Development?</a></li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\">Why Should I Consider Attending a Web Development Bootcamp?</a></li>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n<li>How Long Does it Take to Land a Job After Bootcamp?</li>\n<li>What Mentality Must Someone Have To Find a Job in Tech?</li>\n</ul>\n<h2 id=\"Why-You-Could-Consider-a-Career-Change-into-Web-Development\"><a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\" aria-label=\"Why You Could Consider a Career Change into Web Development permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Could Consider a Career Change into Web Development</h2>\n<p>Web development is one field where you can break-in without a college degree majoring in some technological discipline. The need for developers, data scientists, cybersecurity specialists and many other types of programmers and developers is on the rise. Don’t miss something from that sentence. There are a wide variety of growing fields in the tech job market, of which web development is one. </p>\n<p>The job market is competitive, it takes a lot of effort, a lot of networking and building relationships and a little bit of luck to break into tech full-time, but it is possible because the resources to attain the skills necessary to do the job are readily available for free, with minimal cost, or sometimes with more than minimal cost. Nevertheless, switching careers is such a difficult task to undertake, you must be desparate for the change. You have to be willing to go all-in with time, money, effort, and focus. </p>\n<h3 id=\"Why-I-Had-to-Switch-Careers\"><a href=\"#Why-I-Had-to-Switch-Careers\" aria-label=\"Why I Had to Switch Careers permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Had to Switch Careers</h3>\n<p>The year was 2016; I found myself and my family in a desperate situation. We had moved to New Jersey/Metro New York as part of a Christian ministry, and we have moved without having a full-time job in place. At the time, having an earned PhD from an accredited instituion, I was teaching online for a couple of also-accredited schools. I was able to add to that a part-time gig teaching formal and informal logic, bible and theology at a private school. Honestly, I thought we could make it while I sought either regular Professorship or simply transitioning from my previous full-time job in academic administration to a new institution in the New York area. The NY/NJ MSA is home to hundreds of institutions of higher learning, certainly I could get one to hire me. Fast forward three years, a few hundred applications, a dozen or so interviews, being passed over as a finalist half of those times, and zippo offers.</p>\n<p>I was loving life serving a loving group of people as one of their pastors, but my family was just scraping by. The more time that passed, the more useless my resume became, as I had to explain my increasingly longer employment gap. We were on the brink of bankruptcy, and I needed marketable skills where I would be in demand. </p>\n<p>Before plunging headlong into the  humanities, I completed and enjoyed several years of computer science courses between high school and my first year of college, albeit twenty years prior and with languages like Basic, Pascal and Fortran. Still, even as I pursued philosophy and theology over coding and programming, I never lost my love for tech, becoming the de facto software trainer whatever job I found, culminating in my last academic job, which I loved, in Institutional Research,  where I got to play around with SQL queries and advanced Excel spreadsheet programming. It only made sense that I pursue something like web development. Moreover, I was living just a few miles from Silicon Alley - NY has a bustling tech scene and I wanted in, I needed in. </p>\n<p>I didn’t fully realize at the time all of what it was going to take to break in, but I was in desparate need and I knew that I could do it and would like doing it.</p>\n<h2 id=\"Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\"><a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\" aria-label=\"Why You Should Consider Attending a Web Development Bootcamp permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Should Consider Attending a Web Development Bootcamp</h2>\n<p>As a preface, let me once again express that I sympathize with those in economic situations where this is not a real possibility. Let me encourage you to look to all those who have worked hard to become quality self-taught programmers. They have put in the long hours and many, many months (sometimes years) to better themselves with marketable skills. I would highly recommend free online bootcamps like <a href=\"https://freecodecamp.org\">FreeCodeCamp</a> and edX courses like <a href=\"https://www.edx.org/course/cs50s-introduction-to-computer-science\">Harvard’s CS50</a></p>\n<p>Coding Bootcamps are designed to impart to students techinical training and programming skills that are valuable to employers. They are high-paced, very intense, and can take anywhere from 6 weeks to 6 months to complete. Most require significant pre-bootcamp coursework - usually the fundamentals of HTML/CSS/JavaScript or other primary coding languages. Depending on the duration of the program, they will require anywhere between 20 and 30 hours of time outside of class for homework and projects, and the more time you put in on, the better return you will have on the investment. They are not cheap. Some will offer free tuition in exchange for a hefty chunk of your salary from your first full-time gig, others want cash upfront, with costs ranging between $10,000 and $20,000. </p>\n<h3 id=\"Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\"><a href=\"#Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\" aria-label=\"Why I Chose to Take Out Loan for an In Person Bootcamp Experience permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose to Take Out Loan for an In-Person Bootcamp Experience</h3>\n<p>I chose to go into debt and pay to attend an in-person, intensive coding bootcamp. And, after going through the experience I still recommend it. Here are the reasons behind my decision:</p>\n<p><strong>First</strong>, I am an academic at heart, who loves teaching in the classroom, and yet I also have years of intense experience teaching and administering online courses. I know from experience that classrooms and face-to-face instruction/interaction seemed ideal for learning new stuff, especially new stuff that was going to lead to a new career. (Trust me, I know how impersonal and sometimes how downright crappy online instruction can be - get a bad curriculum or bad instructor or bad grader or a bad school just looking to turn a buck, and good luck!). </p>\n<p><strong>Second</strong>, I know myself. While I have no problem learning things independently, I also am a very eclectic and distracted learner. I can be reading Plato’s <em>Phaedrus</em> one day and watching <a href=\"https://www.youtube.com/user/periodicvideos\">Periodic Videos</a>, <a href=\"https://www.youtube.com/user/numberphile\">Numberphile</a> or <a href=\"https://www.youtube.com/channel/UC6107grRI4m0o2-emgoDnAA\">SmarterEveryDay</a> the next. I could see myself pouring into some online tutorials, and then getting sidetracked by Melville’s <em>Moby Dick</em> for a week or three. I needed a rigorous schedule with clear goals and guidelines. </p>\n<p><strong>Third</strong>, I know from experience and study the value of a learning community. We need people to challenge us, to push us, to correct us, and to interact with us, as humans, in general. Personally, I need people around me on the same journey. Online community is great, and the coding community on Twitter, blogs, Gitter, Slack, whereever is great, but still not the same as people in person.</p>\n<p><strong>Fourth</strong>, I desired some sort of organization that has connections with companies for job training and job placement. I didn’t know anyone who lived in my region who could help me get an <em>in</em> for a job. Most bootcamps have some sort of relationship with local and sometimes national and international businesses and they also have some sort of name recognition outside of those relationships. Moreover, I figured there would be previous graduates from the bootcamp who could be an advocate for an open position in my local area.</p>\n<h4 id=\"So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\"><a href=\"#So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\" aria-label=\"So then I had to choose which bootcamp would I seek to attend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>So, then I had to choose, which bootcamp would I seek to attend?</h4>\n<p>I knew nothing about recent technology or what to begin learning. My dev buddies mentioned things like Angular or React, which sounded eerily foreign to me at the time, even if they sounded like cool names for a night club. I always wanted to learn more MySQL, and I’d heard of Java, and JavaScript, though I didn’t know they weren’t even related languages to one another. </p>\n<p>Where to begin and which school was going to take me there? </p>\n<p>I found in my local area there were a few of bootcamps in Manhattan—The Flatiron School, General Assembly, Fullstack Academy, to name a few—but I found just one on the Jersey-side of the Hudson. They had started up a year earlier, graduating a few folks. I could check out their projects online. It was Rutgers Coding Bootcamp. </p>\n<p>Nothing against the programs I didn’t choose; plenty of folks jump into tech after completing those courses. I found that each of the programs all had similar curricula. I ended up choosing Rutgers, and I’m glad I did. </p>\n<p>If you live near a large city with major universities, odds are you will find a <a href=\"https://www.trilogyed.com/\">Trilogy Education Bootcamp</a>. Honestly, I can’t more highly recommend them. Of course as an alumnus of a bootcamp, I can sound biased. But I’m not saying any bootcamp is perfect. None are, but in spite of the imperfections here is why I chose to go with them at <a href=\"https://bootcamp.rutgers.edu/coding/\">Rutgers Coding Bootcamp</a>. Maybe some of my reasons will resonate with you.</p>\n<h2 id=\"Why-I-Chose-a-Bootcamp-by-Trilogy-Education\"><a href=\"#Why-I-Chose-a-Bootcamp-by-Trilogy-Education\" aria-label=\"Why I Chose a Bootcamp by Trilogy Education permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose a Bootcamp by Trilogy Education</h2>\n<p><strong>Financial Assistance</strong>: I really needed financial assistance to attend a bootcamp. I couldn&#x26;t afford to work for a discount after graduation, so the <em>free-now/pay-later scheme</em> was highly unattractive to me. Also, I had no assets to foot the bill on my own and I probably couldn’t qualify for an affordable personal loan. Most of the loans offered through other bootcamps were high interest (12–15%) and I wanted to take advantage of the fact that in the US, student loan interest can be tax deductible. Being connected to a major university, I could qualify for a student loan through Sallie Mae with a decent interest rate.</p>\n<p><strong>Relevant Curriculum</strong>: I asked my buddies to look at Rutger’s Curriculum and they all gave it a stamp of approval. They were teaching the newest tech that was in the most demand at the time. Moreover, the bootcamp advertised they were in constant communication with employers and updating their curriculum to fit the needs of the market. Trilogy continues to tweak its curriculum to meet local market needs, from a brief perusal over various programs around the country, and they are adding tracks in other in-demand fields like data science and cybersecurity. </p>\n<p><strong>Appropriate Pace</strong>: There are some bootcamps that require 40–60 hours per week of your time to complete, just in class! I found this undesirable for a couple of reasons. <em>Firstly</em>, there is only so much new content you can consume and internalize within a given period of time, especially if your goal is to master that material. At some point, the law of diminishing returns begins to apply. <em>Secondly</em>, I was already committed to 40+ hours of time between my teaching responsibilities and my ministry position. I could not give that much time, nor afford to stop working. What stood out about Rutgers is that they offered two timelines—a full-time twelve-week curriculum, or a twenty-four week flex curriculum. I preferred the longer curriculum to allow myself to dedicate between 20 and 30 hours outside of the ten hours of class time to learning and to also allow myself to continue to supplement my instruction with other training materials, books, and projects online. </p>\n<p><strong>Name Recognition</strong>: I’m sure employers are familiar with the various bootcamps in Manhattan, but Rutgers University has global name recognition. It’s a major research university, renowned for its academic standards (if not for it’s athletics). I have no clue where my career will take me in twenty years, but twenty years from now, who knows what bootcamps will still be around. My resume will always have Rutgers University attached to it. Even if the Bootcamp is in the Continuing Education department, I still have a certificate issued and sealed by the University. I’m a Rutger’s Alum. On LinkedIn, I rarely come across a job opening at a company that hasn’t hired a Rutger’s graduate - instant connection. </p>\n<h2 id=\"In-Conclusion\"><a href=\"#In-Conclusion\" aria-label=\"In Conclusion permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In Conclusion</h2>\n<p>I hope posting some of my own personal rationale behind my choices can be helpful to you. You will certainly have different circumstances and different criteria to base your decisions upon. I respect that.</p>\n<p>The next time I post in this series I want to handle the next three questions, though I might split it up even more:  </p>\n<ul>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n</ul>","id":"6e220122-4ed6-5aea-8f9a-ef9da266b59a","timeToRead":10,"frontmatter":{"date":"2019-04-10","path":"/blog/switching-careers-and-decisions-along-the-way.html","tags":["2ndCareerDev","development","bootcamp"],"title":"#2ndCareerDev - Switching Careers and Attending Bootcamp???","featuredAlt":"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017","redirect_from":null}}],"bootcamp":[{"excerpt":"Changing careers is tough.  For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.539550374687764%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABSy6MV5lEf//EABwQAAIBBQEAAAAAAAAAAAAAAAECAAMREiEiM//aAAgBAQABBQINSnJawMX1bRyIn//EABURAQEAAAAAAAAAAAAAAAAAABEA/9oACAEDAQE/AVm//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BR//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhMTJS/9oACAEBAAY/AslKsGxBXLf/xAAcEAACAgIDAAAAAAAAAAAAAAAAARExIWGhseH/2gAIAQEAAT8hRw3nRKuZ7LEuBZVq8KCJSVScH//aAAwDAQACAAMAAAAQ99//xAAWEQEBAQAAAAAAAAAAAAAAAAABERD/2gAIAQMBAT8QSJMf/8QAFhEBAQEAAAAAAAAAAAAAAAAAABFR/9oACAECAQE/EIrX/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARITFRcYH/2gAIAQEAAT8QDKbViX7BgkAyl1W3yFrM6UcQjVscfZgKoItBvYZVbHA8T//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        title=\"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017\"\n        src=\"/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg\"\n        srcset=\"/static/30874b6095537c9af16ed94f9b05bc86/afcd2/bootcamp-graduation.jpg 300w,\n/static/30874b6095537c9af16ed94f9b05bc86/82472/bootcamp-graduation.jpg 600w,\n/static/30874b6095537c9af16ed94f9b05bc86/c35de/bootcamp-graduation.jpg 1200w,\n/static/30874b6095537c9af16ed94f9b05bc86/de376/bootcamp-graduation.jpg 1201w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>Changing careers is tough. </p>\n<p>For many people, it is also an absolute necessity. As valuable as a good college education is for one’s development intellectually, morally, and socially, graduation does not guarantee a life-long career. The more degrees one obtains come higher-level and yet more narrow opportunities. Such opportunities fade into nothing if just can’t break-in your desired field. </p>\n<p>Over the past three years I have received several phone calls, emails, and direct messages asking me for advice, whether or not one of my friends or their loved ones should consider a career change like I did. </p>\n<p>There are a lot of very talented, highly educated people stuck in low-paying, dead-end jobs, or who just can’t break in to their dream field. </p>\n<p>I’m writing this post for them and for the many others out there like them. I want to answer some of the most commonly asked questions I have received. I want to be specific to my particular set of choices, recognizing that everybody’s situation is different. I also want to humbly admit that I’m writing from a Western, middle class perspective. Not everyone is afforded the types of opportunities from which I have derived great benefit. This may look different for someone in a developing country, and the sets of choices you have will lean away from formal programs that cost a lot of money. If this is you reading this post, I sympathize with you and want to be an encouragement to you in any way I can. Hit me up <a href=\"https://twitter.com/wesleylhandy\">on twitter</a> and ask me any questions you got. </p>\n<p>This is the first post in a series on my decision to switch careers, attend a bootcamp, and land my first dev job. This post will cover the first two questions in the list below:</p>\n<h2 id=\"Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\"><a href=\"#Questions-Ill-Answer-to-Aid-Your-Decision-Making-Process-Through-This-Series\" aria-label=\"Questions Ill Answer to Aid Your Decision Making Process Through This Series permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Questions I’ll Answer to Aid Your Decision Making Process Through This Series</h2>\n<ul>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\">Why Should I Consider a Career Switch Into Web Development?</a></li>\n<li class=\"task-list-item\"><input type=\"checkbox\" checked disabled> <a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\">Why Should I Consider Attending a Web Development Bootcamp?</a></li>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n<li>How Long Does it Take to Land a Job After Bootcamp?</li>\n<li>What Mentality Must Someone Have To Find a Job in Tech?</li>\n</ul>\n<h2 id=\"Why-You-Could-Consider-a-Career-Change-into-Web-Development\"><a href=\"#Why-You-Could-Consider-a-Career-Change-into-Web-Development\" aria-label=\"Why You Could Consider a Career Change into Web Development permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Could Consider a Career Change into Web Development</h2>\n<p>Web development is one field where you can break-in without a college degree majoring in some technological discipline. The need for developers, data scientists, cybersecurity specialists and many other types of programmers and developers is on the rise. Don’t miss something from that sentence. There are a wide variety of growing fields in the tech job market, of which web development is one. </p>\n<p>The job market is competitive, it takes a lot of effort, a lot of networking and building relationships and a little bit of luck to break into tech full-time, but it is possible because the resources to attain the skills necessary to do the job are readily available for free, with minimal cost, or sometimes with more than minimal cost. Nevertheless, switching careers is such a difficult task to undertake, you must be desparate for the change. You have to be willing to go all-in with time, money, effort, and focus. </p>\n<h3 id=\"Why-I-Had-to-Switch-Careers\"><a href=\"#Why-I-Had-to-Switch-Careers\" aria-label=\"Why I Had to Switch Careers permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Had to Switch Careers</h3>\n<p>The year was 2016; I found myself and my family in a desperate situation. We had moved to New Jersey/Metro New York as part of a Christian ministry, and we have moved without having a full-time job in place. At the time, having an earned PhD from an accredited instituion, I was teaching online for a couple of also-accredited schools. I was able to add to that a part-time gig teaching formal and informal logic, bible and theology at a private school. Honestly, I thought we could make it while I sought either regular Professorship or simply transitioning from my previous full-time job in academic administration to a new institution in the New York area. The NY/NJ MSA is home to hundreds of institutions of higher learning, certainly I could get one to hire me. Fast forward three years, a few hundred applications, a dozen or so interviews, being passed over as a finalist half of those times, and zippo offers.</p>\n<p>I was loving life serving a loving group of people as one of their pastors, but my family was just scraping by. The more time that passed, the more useless my resume became, as I had to explain my increasingly longer employment gap. We were on the brink of bankruptcy, and I needed marketable skills where I would be in demand. </p>\n<p>Before plunging headlong into the  humanities, I completed and enjoyed several years of computer science courses between high school and my first year of college, albeit twenty years prior and with languages like Basic, Pascal and Fortran. Still, even as I pursued philosophy and theology over coding and programming, I never lost my love for tech, becoming the de facto software trainer whatever job I found, culminating in my last academic job, which I loved, in Institutional Research,  where I got to play around with SQL queries and advanced Excel spreadsheet programming. It only made sense that I pursue something like web development. Moreover, I was living just a few miles from Silicon Alley - NY has a bustling tech scene and I wanted in, I needed in. </p>\n<p>I didn’t fully realize at the time all of what it was going to take to break in, but I was in desparate need and I knew that I could do it and would like doing it.</p>\n<h2 id=\"Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\"><a href=\"#Why-You-Should-Consider-Attending-a-Web-Development-Bootcamp\" aria-label=\"Why You Should Consider Attending a Web Development Bootcamp permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why You Should Consider Attending a Web Development Bootcamp</h2>\n<p>As a preface, let me once again express that I sympathize with those in economic situations where this is not a real possibility. Let me encourage you to look to all those who have worked hard to become quality self-taught programmers. They have put in the long hours and many, many months (sometimes years) to better themselves with marketable skills. I would highly recommend free online bootcamps like <a href=\"https://freecodecamp.org\">FreeCodeCamp</a> and edX courses like <a href=\"https://www.edx.org/course/cs50s-introduction-to-computer-science\">Harvard’s CS50</a></p>\n<p>Coding Bootcamps are designed to impart to students techinical training and programming skills that are valuable to employers. They are high-paced, very intense, and can take anywhere from 6 weeks to 6 months to complete. Most require significant pre-bootcamp coursework - usually the fundamentals of HTML/CSS/JavaScript or other primary coding languages. Depending on the duration of the program, they will require anywhere between 20 and 30 hours of time outside of class for homework and projects, and the more time you put in on, the better return you will have on the investment. They are not cheap. Some will offer free tuition in exchange for a hefty chunk of your salary from your first full-time gig, others want cash upfront, with costs ranging between $10,000 and $20,000. </p>\n<h3 id=\"Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\"><a href=\"#Why-I-Chose-to-Take-Out-Loan-for-an-In-Person-Bootcamp-Experience\" aria-label=\"Why I Chose to Take Out Loan for an In Person Bootcamp Experience permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose to Take Out Loan for an In-Person Bootcamp Experience</h3>\n<p>I chose to go into debt and pay to attend an in-person, intensive coding bootcamp. And, after going through the experience I still recommend it. Here are the reasons behind my decision:</p>\n<p><strong>First</strong>, I am an academic at heart, who loves teaching in the classroom, and yet I also have years of intense experience teaching and administering online courses. I know from experience that classrooms and face-to-face instruction/interaction seemed ideal for learning new stuff, especially new stuff that was going to lead to a new career. (Trust me, I know how impersonal and sometimes how downright crappy online instruction can be - get a bad curriculum or bad instructor or bad grader or a bad school just looking to turn a buck, and good luck!). </p>\n<p><strong>Second</strong>, I know myself. While I have no problem learning things independently, I also am a very eclectic and distracted learner. I can be reading Plato’s <em>Phaedrus</em> one day and watching <a href=\"https://www.youtube.com/user/periodicvideos\">Periodic Videos</a>, <a href=\"https://www.youtube.com/user/numberphile\">Numberphile</a> or <a href=\"https://www.youtube.com/channel/UC6107grRI4m0o2-emgoDnAA\">SmarterEveryDay</a> the next. I could see myself pouring into some online tutorials, and then getting sidetracked by Melville’s <em>Moby Dick</em> for a week or three. I needed a rigorous schedule with clear goals and guidelines. </p>\n<p><strong>Third</strong>, I know from experience and study the value of a learning community. We need people to challenge us, to push us, to correct us, and to interact with us, as humans, in general. Personally, I need people around me on the same journey. Online community is great, and the coding community on Twitter, blogs, Gitter, Slack, whereever is great, but still not the same as people in person.</p>\n<p><strong>Fourth</strong>, I desired some sort of organization that has connections with companies for job training and job placement. I didn’t know anyone who lived in my region who could help me get an <em>in</em> for a job. Most bootcamps have some sort of relationship with local and sometimes national and international businesses and they also have some sort of name recognition outside of those relationships. Moreover, I figured there would be previous graduates from the bootcamp who could be an advocate for an open position in my local area.</p>\n<h4 id=\"So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\"><a href=\"#So-then-I-had-to-choose-which-bootcamp-would-I-seek-to-attend\" aria-label=\"So then I had to choose which bootcamp would I seek to attend permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>So, then I had to choose, which bootcamp would I seek to attend?</h4>\n<p>I knew nothing about recent technology or what to begin learning. My dev buddies mentioned things like Angular or React, which sounded eerily foreign to me at the time, even if they sounded like cool names for a night club. I always wanted to learn more MySQL, and I’d heard of Java, and JavaScript, though I didn’t know they weren’t even related languages to one another. </p>\n<p>Where to begin and which school was going to take me there? </p>\n<p>I found in my local area there were a few of bootcamps in Manhattan—The Flatiron School, General Assembly, Fullstack Academy, to name a few—but I found just one on the Jersey-side of the Hudson. They had started up a year earlier, graduating a few folks. I could check out their projects online. It was Rutgers Coding Bootcamp. </p>\n<p>Nothing against the programs I didn’t choose; plenty of folks jump into tech after completing those courses. I found that each of the programs all had similar curricula. I ended up choosing Rutgers, and I’m glad I did. </p>\n<p>If you live near a large city with major universities, odds are you will find a <a href=\"https://www.trilogyed.com/\">Trilogy Education Bootcamp</a>. Honestly, I can’t more highly recommend them. Of course as an alumnus of a bootcamp, I can sound biased. But I’m not saying any bootcamp is perfect. None are, but in spite of the imperfections here is why I chose to go with them at <a href=\"https://bootcamp.rutgers.edu/coding/\">Rutgers Coding Bootcamp</a>. Maybe some of my reasons will resonate with you.</p>\n<h2 id=\"Why-I-Chose-a-Bootcamp-by-Trilogy-Education\"><a href=\"#Why-I-Chose-a-Bootcamp-by-Trilogy-Education\" aria-label=\"Why I Chose a Bootcamp by Trilogy Education permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why I Chose a Bootcamp by Trilogy Education</h2>\n<p><strong>Financial Assistance</strong>: I really needed financial assistance to attend a bootcamp. I couldn&#x26;t afford to work for a discount after graduation, so the <em>free-now/pay-later scheme</em> was highly unattractive to me. Also, I had no assets to foot the bill on my own and I probably couldn’t qualify for an affordable personal loan. Most of the loans offered through other bootcamps were high interest (12–15%) and I wanted to take advantage of the fact that in the US, student loan interest can be tax deductible. Being connected to a major university, I could qualify for a student loan through Sallie Mae with a decent interest rate.</p>\n<p><strong>Relevant Curriculum</strong>: I asked my buddies to look at Rutger’s Curriculum and they all gave it a stamp of approval. They were teaching the newest tech that was in the most demand at the time. Moreover, the bootcamp advertised they were in constant communication with employers and updating their curriculum to fit the needs of the market. Trilogy continues to tweak its curriculum to meet local market needs, from a brief perusal over various programs around the country, and they are adding tracks in other in-demand fields like data science and cybersecurity. </p>\n<p><strong>Appropriate Pace</strong>: There are some bootcamps that require 40–60 hours per week of your time to complete, just in class! I found this undesirable for a couple of reasons. <em>Firstly</em>, there is only so much new content you can consume and internalize within a given period of time, especially if your goal is to master that material. At some point, the law of diminishing returns begins to apply. <em>Secondly</em>, I was already committed to 40+ hours of time between my teaching responsibilities and my ministry position. I could not give that much time, nor afford to stop working. What stood out about Rutgers is that they offered two timelines—a full-time twelve-week curriculum, or a twenty-four week flex curriculum. I preferred the longer curriculum to allow myself to dedicate between 20 and 30 hours outside of the ten hours of class time to learning and to also allow myself to continue to supplement my instruction with other training materials, books, and projects online. </p>\n<p><strong>Name Recognition</strong>: I’m sure employers are familiar with the various bootcamps in Manhattan, but Rutgers University has global name recognition. It’s a major research university, renowned for its academic standards (if not for it’s athletics). I have no clue where my career will take me in twenty years, but twenty years from now, who knows what bootcamps will still be around. My resume will always have Rutgers University attached to it. Even if the Bootcamp is in the Continuing Education department, I still have a certificate issued and sealed by the University. I’m a Rutger’s Alum. On LinkedIn, I rarely come across a job opening at a company that hasn’t hired a Rutger’s graduate - instant connection. </p>\n<h2 id=\"In-Conclusion\"><a href=\"#In-Conclusion\" aria-label=\"In Conclusion permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In Conclusion</h2>\n<p>I hope posting some of my own personal rationale behind my choices can be helpful to you. You will certainly have different circumstances and different criteria to base your decisions upon. I respect that.</p>\n<p>The next time I post in this series I want to handle the next three questions, though I might split it up even more:  </p>\n<ul>\n<li>How Can I Prepare for a Coding Bootcamp? </li>\n<li>What Do You Learn in a Coding Bootcamp?</li>\n<li>What Does a Coding Bootcamp not prepare you for?</li>\n</ul>","id":"6e220122-4ed6-5aea-8f9a-ef9da266b59a","timeToRead":10,"frontmatter":{"date":"2019-04-10","path":"/blog/switching-careers-and-decisions-along-the-way.html","tags":["2ndCareerDev","development","bootcamp"],"title":"#2ndCareerDev - Switching Careers and Attending Bootcamp???","featuredAlt":"11 Women and 11 Men graduate from Rutgers Coding Bootcamp - May 6, 2017","redirect_from":null}}],"intro":[{"excerpt":"This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 1200px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 52.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwACBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHjYtEUEP8A/8QAGxAAAgMAAwAAAAAAAAAAAAAAAQIAERIDBCH/2gAIAQEAAQUCtb62WVlzCcjj8WyZ/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEDAQE/ATF//8QAFxEBAAMAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAgEBPwGIDlf/xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIRITFh/9oACAEBAAY/AuNk04q/Sm9MwlRbP//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExUUH/2gAIAQEAAT8hK1J4EshDT4l0DhmIJu5HcwQi2y1n/9oADAMBAAIAAwAAABAcH//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxBLqL//xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAgBAgEBPxABX//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQWFRocH/2gAIAQEAAT8QWJfQg8dr6ioJ1ByR+k52ZRsu3UZ2ib0vEZnkR7jlCrVn/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Code displayed on a computer\"\n        title=\"Code displayed on a computer\"\n        src=\"/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg\"\n        srcset=\"/static/41ced244a3d93044daa17132fdbf446a/afcd2/batman-coder.jpg 300w,\n/static/41ced244a3d93044daa17132fdbf446a/82472/batman-coder.jpg 600w,\n/static/41ced244a3d93044daa17132fdbf446a/c35de/batman-coder.jpg 1200w\"\n        sizes=\"(max-width: 1200px) 100vw, 1200px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>This site has needed an update for a long time. The last time I published a new professional portfolio was two years ago when I graduated from Rutger’s University Coding Bootcamp. I didn’t have even have a regular full-time developer position yet. I was still hopeful, dreaming, a little naïve, yet expecting great things. I was ready to go to work and code hard! But that site did little more than highlight some of my work, projects that were good but not production quality. The page was overcoded - a single page with five sections but templated via <code class=\"language-text\">handlebars.js</code> (I should have been serving a single html file... <img class=\"emoji-icon\" alt=\"emoji-unamused\" data-icon=\"emoji-unamused\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAULUlEQVR4Ae2bBZAcR7auv5NZ1TCkIWkEHrGM1w5bqzVbZlhm3r3MjMvMcBn2MpuWmZkNWjPbAq9wmHqaqjLP6+rOuOrokMao9aMT+iOzqep8f57srKzW8P/j/+n4//H/QzjG8XYwr341GyPlVAyniLBZYKWx0o/SBYBQ9k5nFQ6p8hCeu1PhzquvZhfgj6kBbz820LL7NZypwnNjyxUmlpNtbLpMzmByghgB2+G9U9Qrvp7J4xJf9onekzi+KspnN/w3NwH6v3UF7HgOXUP9vNRYfjFXMOfZojGmy2LyGbgixiNWGxKQjlOroi6ToN7g64KveXzZ4Sre16v+B97xb1OzfBQoP2kGNJJ+wrGwQLR+lFdHsfxRrmh+xvZGmG6DLSgm9kg+hyn2Y/tWQ/cKpGslkutBTA4A9XW0XkLLh2BxHDd/AF+ZRWt1fGJwVcEvetxCSr3i70oT/bM9e7kaSJ+wAd+6iCcUq1dzZiHmvYUee2m0LCLqs0jeYQoRUf8oZuUZmJGnIT2bkcIgRF0gFoS2ihZQQB2kZbQ6jZYewo/9GH/oVtLZvfhqitYs6bwjnUupltw3qglvBG56Qgbc/0oeV5xwLbLrVfxhoUvekRuIu21/3GDzmK6IaORU7LorMMvPhOJggEsBDxqgBVCO0BfAgEQgQGUaP3ET7uGvko7diS+npGWDm02ozySL1bK+beM1/DmgP63vANnxEvqWF/nbQq99dTycI1pmsUVHtOJ47OYXYVacDVEBtA7qEDE8nlD1oVpykFbx4zfgHvoE6fgDuIolnXMkk3WqC+7qiQq/ve1jzAN6LA2QW57LqsFBrulaFl0Uj+SIeoWop9FuuhKz/kVIvh98FQEQeXxnUzqdQAFMAa3N4vc0TNj5FdJSnXRBScbqlOfSb09P86qtn+UgoE++AQF+eJBPF4bip+eX57G9EA0MEJ30CszIBaAJggeRJ3eN0XYjDEiMH/se6b3Xkc7M4BagNlGjOpXcPDnN8x+LCdGjhf/ylQw04K9rwq/M4IV4YIjolF9CBk5C3BwgIIBybAwARAHKmBVnEse9yN3/CnaKvM0DPH2Y5LpGri+46ivMAPpkGCCAOXElf10YiLbnV+SxfaYB30900mswfeshmQEx7fDHzAAAFMRVkMa5o5NfA/f+J8gseZ8Hr9tP1PSvgZ8DPKCP34AA/8Cr+cNin31VvCJH1G+JehvtxmchPaOQzrbg9YkDP2ZD0mozhywXHvg4Qh3vcxRTfdUDr3a3H381f/5IJsgjwf/wJTxt/YB8s7Cm0J1bnifqg2j0fMyay4AURBAA4acbGqhUgQi//+uke79POg/17Ptgf3Vxz4xecu7H+PFSJkRLwb9mhMKaXj6UH4q744GYqMdgB1Zihs8AvwgoEuifCgMEbfEjzZxsaRf4Q2gao1XXvSatf6jB8Mz/HqNKMOExGfCmy3hZscdujxrwtifGFA1m6GfAGnDlFrwIT2WIBhNshBk6FS1PYFMhGnAUF932N13mXvbf1/DfgD46AwL8G86krzsvr23C9zZUEEzPcPM6HldCREGfgpE/WiV4QbpGmjnaZALfGzdN6C75177hTP3M+25irs2EJQ0wgH3FZl6U77MnRH0RpthQ3iA9a0AU8eWlR/6pqgSJmjma8lQz5yz3fF96wis2py9qGPCfAd4tZYBkOmuQfG9Bfinqs5juCFswSD6PFJYhvgL48M6wrzfBjNSDV45pGIHIAIBXcAqaCYQEshzzeWxSw3dHZAy98+6XzhrU62+cxgVGXcoA+/7tbC12yTbbE2EKFpMzSK6ImAhcBWJpyOAWE8YmFplfqBNHhpUruukeLEDiwT3JRtjWORenqxwaXyRJPX29OUaWd2O749Y5E23mmOVqckkz94yh2JVse/923Xrxp/kR4JcywAB2pMc8N+6xzZsZNmeRyECUB3FQUCYPlvjKt37CTbceZHKiRK2WYozQ01fgrK1rePkLjmdZfx4Sz5MSsWFutsb1n3qAG2/ZT2m+ivdKPh8xvLyHM89YxZUXr2V4VQ9UfTPXLOcsd9dgyFhGengu+JsAB/gjGSCA2ThAXCzoxdK8k2OR2CCRYOIYTJ0vf+lhrv3EA0yNV+jKQV+PpW9ZjHOe+ekSH/v4/dx250He9fozGR7Mg9MnthuywuR4jbe8/yYevH+e4X7o78thraFeTTiwe4pr75/iK9/cyStfdDxXXbqumauPpJl7xpCxFAvpxRnbrhnS9mlgOg1429PYmC/ICbZokZzFNA2wYBz/dvXd/NWHbyct17jwik388huu5A//7KW89s9f1tTvvfcFvOQXn8ZUxbDjjkmwKfgauCq4MqQlSBcgmYdkFpKZTKE/33otLbXe66qtz9o0O1Z2zOaxs3OE8zXPneWQ5ZLllOWW5YhxSBRyz1kylowpYwvMcrQKsKO9nBrlTdHkDSZz0TZUiPjo5w9w7ccm2LptOa/8rbM5/ZQhqC9COUs6BRE2L89xzrbNvOJn1xFNH4K5faAe1AHa6qNHucCXw62Y0FqoGbZfsIxzn3cJfV0xVKpQnQRV6I04ZX0fV15xAbfdfTLX/t0NjRx30hMv56XP6EVqrsmQsWRMo73+VOCBpQww/UVzss0LEmfwBlOw3Pdgjf/4xATbr1jN77/+bPr8Ijx0N3gXAFPwSavF0Zcz4IHUdyyXnf2jXeOmoZuAKl2VChw8BHUPWJAITNxqxYCxnD46yMYPXsBfvv+GRq4HOG1zjhPXWmTRNFkypowN/KeOZoDJlI90k0SmBR8JiuHqz0+x4eRl/NFrj6N7+kFYSMAKqGsJbWMyUAckjOATvVktgANSbcGiQNIynHAOZ2HvAn29cTPH104sNnKe5V2/uTxUsSFjykfpJgJnpwESZGNhBZE0AaPIsHcsZfe08o53rKV7dg7m6mAEHG2jK8f+5xaRo9wkcUAKAHM1urXOH/z+Wt72tp3sH0s5rsdQtwKR0GQD28arpiPt2Eb0h/v2IFAT4Rd+dZTN/Q5mM3jTcSc3SMKhY4GctFrzJO9/DRC1nSMiYIAqYAw6V89ybeZcDQyIkDFlbEC85HeAEQpiQIAkVTasjtm8zKKTFRABPUwtQgAVXMUzOeOYnE1JHHQVDKMrI4p9BuoK+kQugAQSpTTvGJt2lMoeIzA8ELFqRQQWSBVVQKSZ62UnFUnnYpLpFAHEQMZ2tFVAQmuajOhh06spmpZRQEQDuyJ5AQ/3P1jjB7dVuPuhGhPTKUmiaCsTenotz7+kh2c3hHsEE6RjwE1rlOenE264s9ZYCivs2V9nsexxHghQJ27M8ysv7Gf1SIRP2k4wWcY4jwMAlDBgwYAgjTpmlHGeKg40LF/eC6IW2ipd8vDQroT//vwCd9xXQ7ynv8sw1CPkewURIfUwu+j454/O0NUFl1xQRGuKPIpilxjSFD71hTJf+GaJ6emU7pww2GtY0ydYC6pQTZS77qnw5yXHO39riGJO8G0rrTqHakPeg4MmGxjCMB5xL5B65tV71KUNCWgwQ0AQxMJXv1vhL64pUcgLmzbHDA1YSDyVCUd3HuIIFFhWFCKB7+5YbBhgELtEFUhojDC74HnP35W45Z6EDaMRZ2wt0l0UKlMOqbpmXwykTujJG/aMJdz/cIUzTsqhdUA1OODBJYHFk7EtdT9AAWopk03HfOaeQb1B8BCGv1pX6gPCn7xnkJO2RPT1QGwFZ5Uff7fKN/9rkUIsTROsgd68oKqoqRMMWDosTCwqZz4rzy+8vpc1I5ZCDGKF6Tnlk3+zwNyehL4+Q86C90oxEmo4kDqoQKBRrw25wOKbbEfbDWoQc3V5eHWiqFPw4SLHC2oApQn27PMN2AQWqjAbPhrB+WdHHNwTccuXE/p7hSTNDIPLLrNIsQ7lJZZID4TB27LJsGWrgXIFZhQSwMPKfsNzXhPxL+9PSaaVQh5m5pXjNkWceLKgSQoIhOOgLQZNFU20yQbK0aaAAunD837nCXWLd4r3HqMGQUEAA+Bx42HdsYBRMCCJYg6lPPfFluKQ5f4blWIBLr3ccM7pHiYdRMJRw7TNhGoKlfa1PkBNw+ig5TWvi/n6px2lSeW0cyOueGZMfyXF1xQxBoKZvsnvWyx1yNgAd7TtsAfSHxxk16VbfJXEF9QZ1HtAEAOIgnhQbfVtaMNrqpCfTXn2Mw1XPUewBqTmYNKH9zyGe/8EcOWwDOisZ/OAYfMfWOrOkENgfx2/qGDbLswcqA+VnHpczVczNkI9Hc2A5L/uZt8fPp2dhZqeomkoIQwCiNUA35I2JA2BIgQTHMi+lChuH10FeQwGSIcBntBK6xxTikw5ciJo2pBvuyuFEv61ck+0WRmlCjsztqUMUKC2mJCMzcsNQ5kBCeCDANohBCSIw22QgCoYWhKBYNAjXwcE0M7XVJD2xx7Uh745goEOSEEzVZSMaTFpEtUAPZoBCVD5+l7//eNHzS9EVTWuDqagrQTaDegEFwVzpLZDwCOvhQoKQR0RzJUj/A4ZitMr4BSXglaVtKo+YwIqQLLULTEPlP/8Zu57+Sl618igP83WBZ8YbF5AOkbTCEhbMib0/6clvA5AWyuPbhpoJiFEp/vt0yQMkKAecOBTRWseV/HZ8nlXxgSUAyNLGVCZT6jcdkA/fcVyf5pWDXQdLjmJBJEO0ACJ6XjOBNj2VUSAHGAB38ZSbxsboQOOYDaAtBVK6HgBD2hoXSj9mqILnowlY4JMSxug4U3zb/o+3zlr1O8ZXObXm6JgiiA5AzaMfDuQAQhQAtBeHW3J5wGn3HW7cMutcOiQYCNYv045c5syuglIBWqdS2QAQ8C29TWIpsLtCUHrHl/xuAXP3Izfk7EA84HtEX8YSYGFnXMs/Giv/tdV/f6tttvgi2DyQCxh/afdgKAATHslAKLQBT95CP79323TAOMhF4Eq3PA9+MTHle0XKa96tdLbB1Q7KkAEIFSNBFNaEg73NQFfBVdS3KwnY8hYoKkU4JEMUKAEzP7GN/jODav8Lat63VbpalWBiQ1YQSwgtJkR1DlNTQYv3PIj+Ju/MLiysHEYuvJCFPhSBwtV5dtfhp0Pev7otcrKNUCl3QQBCKa2jbwE8EwphHlPOucYm/S3ZAzALFB6LD+O1oDZuSrL/vE2/bvX9bm/k6IpSF6II4+xBiIQETAdJgDQNvpdcPctyl9+yNBrhZGVQj4CS9uuLYZCJHQXYO9ewwff63nLO5WBAYF6MAA6oIMJTlAFdeCrnmRRG/Ce6rSrZrk3GOaDATWOEJajhwOiGw7gL1hpamt79EwTC5kkAqy0TDBtJgjBhAAfw/SE8KH3CFSE/oJggKgI+WVQHIJcD3gDSR2SKuRjGBuHvQeEc88XBA4fWAQI0kxh3tdaa71fUNyMJx13/PBB/vH3v6nfBw4Bk0D6WA3wQdH19+mBF29gpD+vm4ilBR0FIySY8D/wbUtdTviXf1Bu+SGsHRVO22644GWG7S+B854D2y6DMy6FrY12yznCik1CPYH5Sbjtdli9GjacaCAR0GBE+3xPQevgy+DnlaQBXx9L2fmw/+qlH9F/B8aCyo/nv8iE7wKmgeJrPq//9OkX+RUj1p2OQGxArEEQVDRrA3iAF6U2DwenhGf/nOU5rxBWH6dQ91DRML8VgJwIXcPK6Khw7uWGe+8SPvofnvv3eC7xbaUf+jhpglMXtKz4ed+ET8Yd4/v9bVmuwAwwHRj08RgA4ML8ie+bJv/LX9YP/uuz3FtWwEmEnNQLxhnIAzFIFFYAhVwMb31fjkKvwoKDgwqqR7gQEkiABQXxnLTR8LYPRFRnFSoelPZRh0TQGviKz8q+BT+Wwbt7sxwbuR4CxkPujiXC8siRAh7gJ/PIbWPcetGwbuw2uiosRYi2rcuASKsvQOQV5hVqAHKEq7jQp+2LrQKUlMgDTsCZMOqgGXwZtORJ55Q0gz+YcuAn/tZf+aK+//v72N827xcBnqgBAHVAMzVM0K/t5MeXjNDfJ7pJwqCKV8haFTSAiSdA0g7dZlaQtgkB3wImFciAM9UFquAXFZ1vwbspT3LI8dAe/7WXfEb/ujE4B9rg5wCeLAMAaoAHdLqG/NPt3H7msMyNWHeqSYlU2+ZoMAMIpnSs23T0tcOItCVNQZO2b/kSuAx+RpvzvXworX7vfv758uv1mulKE3oMmAilz5NtQDABF4wwH71X9yU1dhxf1JEur6s0vNJsnYAnvFtQ1wboASX0MwEp4AJ4PRNoVdEyLfAFj5vzJFOedMxxYK+/5S9/qB/6o2/qTcBUgA8jjx7T/y0O9AJDQQNFS+/fXcW5F22QF/YPmw12mcH2GkyXIEXB5oCcIDFgQUz75gZQwCsaDGvt2hVXDyNfVlypZcDspN/97d36yd/6Mj+sOBaAGWAqaAHQn9afzPQAy4ABoB/oW9NDz7svYts5o3Ll0ICcGvUYyUywXQbJC5IDCXuJTMYAgA/gaNjB1VutK/smfFryOjWtd/5on37lzd9mx/4SJQhXeDATRr30VPzNUD5UQ18woTcYE/3+NjY8a4vZtmFAt/X0sj5XNHmTFwhXkiZqr4Cwf0+BcAurXvG10gJ7ds/Iji886Hf85Q52A2kAXQjw86Ffeyr/aMoAxQAfRBfQDeQtmOccz4rto6w5YciMDnfp6q6YwXxET2zJAySOWi2lVE6YnizLgfun/N7v7mX/5x5g3IEPgItAOQAHte/vn/qIAvxKYBNwKnAmsB24DHgm8Bzg+cBzgRcAz8sU+s8Nrz0nvPey8Nkzw7E2hWP3AhH/G0cURn8IWANsBk4GTg8w5wDnBbh2nRdeOzO89+Tw2TXhWN3HAlw4diFA3KEotO37RwBtW14TIA1tu/RYJfnTis47B53nVsAHBTOOffwvrHvsx5swbgQAAAAASUVORK5CYII=\" title=\"emoji-unamused\"> ) I had plans on creating a <code class=\"language-text\">mongodb</code> backed blog, and for two years, you would find in the footer of my site <em>Blog Coming Soon</em>. <img class=\"emoji-icon\" alt=\"emoji-thumbsdown\" data-icon=\"emoji-thumbsdown\" style=\"display: inline; margin: 0; position: relative; top: 2px; width: 19px\" src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAATlUlEQVR4Xu1beaymV1l/zjnv+q33fneZlelMW6hdgRJKKS02RjYjRozyjyEhwZigYmJM/MMQ4op/EIhxCYsgxASNFtCgrQiKCZSyWWXaaaG1Mx1mOnefb//effF3nnPovbkw3juGNumVb/K7513PfM/vWc9z7qUffX6EH+H/NcR+Hnrf2+5aJq+1XOXlkqR6rqKikydZmCazKp7E63GcX0wmg/Mfe2zc/0Hvf+Adb+iVorzNVf6rhBA3K0fd4Ch1wlGyWUsRKiEdwqeua6rKgso8pzROsiyeRbPxZH06nZ6ZJek3hVRfvP5Vd66EftNVdd0sVSXqos7zNI1FNR3++p/+8/iHRsC733zbqUan/RuNTvfOZrtzImw0lj3PF0JKfqmuSiqyjJJoRtF0SsPL/UvD/vCh/nD4lx/75urn/ujt954MvPBNYbPxk14Q3hGG4XHXd8l1HFJSkVKC5+GfPCEZ4bOUsiii2aBPo/4WEbhpzC9QMNcj13NJef6IpHLBVUMTVhRFledZnMXpII5mTxXx7IGNtWf+6r2fPbP+fybgt153w9GFI4e/snDk2Mm5hQVqdVrkez65rkPC/oOujLYKEJFnlCUJJUzEFu7Ql+cWl2/2m+2e53vk4D3HARSEdwQI0DNIgsg8ihpzUc2aL0DoFHNMNtaodfgILV5zPakwpBqkFRVsDyTVGpXgsSpKvgYroNl0BtIGtLmy2l9fXXvrB77w+L/tRYD8QRc73e7v9pYPn1w6fIiWlxapt7hA84cXqbvco+7hBeoewvkyoO8t9WhxcZGWjxym5aOH6CW33ko33f6Ke46dOokplnCvh/ct8P485uoCc3NtoEudTpPaILjTwthqUMMHUUVGR06epFO33Ead3hwsoE3hfIPCXhPvdqi71MN3mOfvMn9okRbm56i30AMWaAFz4//qLcw1P/2ue65f2osAZ/eF337DjUcanbm3zuuJ5rvUXpynsN0g6SqS0mgfA9XEP6AJ6K6EKY7G5EvCcx4JpUhA48LDsYvnlSSlHP0+II0NFQWJJKOyLPF+RQQtykKbdE6yzmmuN0+Bfg9uU4c+lUpwjLAmi3cwVHg3A4SgNFfkYIQPwX18IqG6jizvJKJ/vCoC/GbrtZ35bqfdaVOz1aIQWvFCF8IrYncVAsNO01F8licxuaoFU9dfOCDyrKCCGESaCJzX5oKoFAYJwiCYyKnEfSU4EpLUDpZlMO+MnMolNwVZjqIKZOMBJgIvYcQ5rpWOviypkhAIpCiQqSq4Ry3aV20BJNVrWjDHwPfJD4FAa1SSIyULvztw8ElRkScUyYYP4RtUu7X9osbT7Ws24AFFBRREqtbH7MclCEynE2BE48ubFI8G1Lg0T34DpPo+KU2sJqasOABDeLacojAxoYAlxUlKQ1ji5eGYZpMxbQxna1dNgOs5t3haeN/VwYuFl+IKwgPa/CSEkIFPBAKEMq5RWe3LZx+0b2clkBqz1wLlOQewZDik4dpFWj93lqIoQrw5TH6nC/frkucHpFyP3cqmS6DSVsIukycR5oA71RMSMkJWimmjP7nwN4+sP3K1BEjPdU8ox2GTZ3+VrLQr5ks2WRfa8Vybzurd0dUKbzWfJhw3WHwd9UFGOurT4NIFunzpIh2/9WV07MaXUtjtEul5K5AkKvM+m3xtwCTYEdovYQlZntGxaURHV1Zo+cmzvdbSuZ99/wOPfIyZ3icBDlJdTykrvAL2qpVqQNZW+Csk2kqYL50kLFAtrOlb7c36l2m4sUonb7+Djt3yUnadzJV4rqTKqe209bYbAbLmI0N4Lnk+nLOVBO0OMs5y69hw9OF3v/GGL//B5554Yr8EKCGEx9HaBjwJ7MyZ1RWJ2ON6mrGmuNortP9q7YMAmHs8HpEXNKn3omsoi2KS7SYE12ECz1fbU4hdvNr4QtJz+CE5KUmqkuOFghuHYSALIX+eiP5w3y4gpHKt0DbS4iEprCw/WNHVFSqqbb8vSBS5IU+bNISvC11EwYfhEmkcceyocE3qFJoXLJSL47reNb+wwzashVWcZZSSNmgTKWN4p64mBggFBrbTXbWL+d0kWC38b3VmWXPQw0zG92EFpIWHv5YQvsgwFjlQUBpNjZFLhxwQJVyXU6WQlgQ7H0k7udUELIsJ5ciCsU5jKmZTk1nizL0qAmpRsdoNdku3+3Q7xVF9Je1nRnAbrKBmjtxlzjBaB+ejwRZdfvosNbpzVFYV+3bFgpU4L0ngWqGfx1hzyOEfJiaWBWeFMi8pShKaTqZ0eTSlrdGMBtN4xRYr5d4EMJu1rTMEk8Dg4+8jYjunS6mpA2gHafoeTiCkIGv6NYTJCxas0gRkKc4zfjRNUzrz0IO0dPQok+CHIac+Yl2UfFwLAXD0Z1JwQim0XMQxVTjPMecsSmgcZyz8xY1xem6Q/svVEYAEjUJD2UJDMwHs0rDYgTg1BAS+eUjsCAyJ1T4ZLZEWns3fpL8c2srg/zFqgEa7TTfecy8tIhCiGjWxQEijAPthzVjUpg7nRRGItctozAmLm42nNNzcorPfveieeGb19246MvfLH/nq+e/si4AK1MLMXPYrgDQc11rCDpuvjZB1lnOmqKUi8jGdsBYDcxSlCXwwX05/qPu5vK3y7FnhZ6MR5Zj7ZW98M3UOH6ZaW41OgUoZKxTbZiV2kCAAKmueGwEW5w5Jx6NKpeRDrACKO1xUMsvLe5I0/ygR3b0vAkpEJGgtYLYroKzsDUCQIcQyIHCcw5+V65LSBY5qEIffUhMAQc3ihctVsGnLWBMACx2gEKgmWPMvnbqeOotLVKQgs9WgyoPwLO224Rk7kjb+7TBC/UDhkUpArMjJ5bggKID1+q0IltUhP9i6c9+lcF4UGSIya8tEVViCXozYwEQsDCvG5nSwLyVJYQIeyQAEFEBp+apMgILgVDEJ7AJcwuoUiHfQdDE6VpIIwiMMmYLp++Ir5trlhUoIXijVeuWZ56aCxbnC6OCa4wOOo/ZNQJblY6SmBY7A2nTz3JSgSrFQbBmWZdLCZAkIUFTq8lkLnSTWR3HbrtZqgKO5jtY2ABYZp0AOiDmOq9q4ichKUoFj6v0r5B4u0sx1tgBZVqa40nEDJAv9rkbFLmziD6gFsr0JSLMNBJJTiNbaHWzwsX5sDN/kXXaLXPsy+54qXaq1Jdh7JLSfCuMGTAIBIMzOQzwKrjfGCFg1yAA95EyJVO6TcB0TBIXAaKQWZEivrTtRweSamqI2MasogATkxjPuLiXTCSVRrLl090NAPY2SSwkmyLlIybnlpZSywpscjOzAkbcG63ka6z4dzC0gqXBdqe2GRV0xERVgj5kMzuWC3YbT3dqF87R29kk6dPI6woxmuTuFZcQJJeMhpdMp9xsKmzZzCGnLaqDkeTAnZ5g0SSmF8qZZQTEwGEeoCaL7bc1GexIwS7OnosmE4tlMWwPnVhDApSrYBkqTyvSY5pRMZty4VEHIz5AQNlCxV7OmTfyypTUGs9jCnBgd14cACf3nFz5Px1/8Elo6cY2uD7gpmiBICszjNtok4WKu6yGwtQndGt152o49Spp0m2ZcVo/GE8ouXKTzF5+mx1ZGn7j/ic337TcGVBuD6OHJaEzj4YCauhvkufwlSqWjO2vP1vApzCyiCBqqSJAbNokEBMIxmWraRHJr5hbcGiulJIV5Pc+jIvDhai2KphE9+egj9Og3vkY3vuzldO3LX0HNhSXyGk1yPZDrgDybGiqOLfpYjzUHWKOYkqvFEMoLuj3yOvOUO98+9g+PbmZXKoTU7vMkzrJr5oNf8B3Vch3uA5qJU+78cuqKwHCE/D3u9xlIc+wGrBGlTPoSZLRPgo+FJY80mWX9bECtbLCCJrlKPHXTzXT7T/0MNXpL5DZb3GSpXMkolaDKgbY56ksiV4+gXAG11WAtqahrzi5RlFKWRNc1ZPWlx9bG39a397KA8vwkG64OJvc1w61fg+yUQdPtTocC3+MHkCU5yCRgOZ5OmIxWN8FM0GZVs5BBo41TxYTAeli4gstlBTi454JUEAZTd12XSpCHuMJdqKOnrgMxxFoVXggB8S5nJJsPbU+S6u3lsHIl3ndNyqacLaUSii1Tc73UCa4honw/LlAC+eefuPzx0HPugP/fEU1nZHqEHkdj7rwkKelAGccxzcByvdEfvbikblaZ8r8NIsJmi/cRpCO1DRgfBjkFl48uSe0CmLMuG2wJeZmT67haWJ5f4J6MEw7eJQvKXWGGLUZtY4QMQWnKLbI0K3h9kEYxxdGUvye+8747QjWQbkX58DOPrP3mT1zfe8fSJHpdO/APea5ypCQ23wzVUpRmg0Gc/felUfrQuc34az+dVG+5vax+saxqdpkKY7PTIo+gbU5nFYGRZxssHsigEqgxFLAaEJsEEU3QHWotjUmkISldGUYe53dybEoEMLLwhc4WJQc/01sscsrilCbjMQ22NvVuFY6n1I/iR/dJACMFZoO46H/60Y0PdX3nr0/OeS9qBt5c4FAjLep0lOSXLw3T1UFaTq1f0Ye+/PSH3lmL8Laq+jlezrLWgFaTzVxKbnablMpFkyIJjTt+QG5ecE8ghOtsoS/oIKA2EACJ9xhcE1SVxKitid3KxBlGwVZZ5AULn0Dr48GANtc2aH11XS+LH7z/v9bPbDe09iYgB6b2Ho3Soji9XoyJIrndC2GUQMGjneuDD55737sktWoSr4emONUpQDSFbjaaDZOi4lFKkOC63PjwG2ZTNM1guqMJPf7wf2DX5yg1ez0STqAFBxS7kd2XYFSVeS/POStxXJohhQ8xR78/qNZGswfu+9bKeyKict8WYDGzYwE0AA9QOwio7L1sR3DxgdYnHjr3+7/kqDY0/WreD/RMbS50inRMnxxXuGBSnscTqroi5YekVMCt+OE0GfzdP331d+bbjd51x5dumWuFNznSOSKVbEhBrpRC2M3UOsvLssw1CUk8TbLhNE4vrg2Tbz66Pv7KU5vxeavMHKj2T8A2CamdwL0CAfkOCwiBYoKrf/vwxfe83XM/6Pve9a4PoZTD6VEKbc62oyvNfkOtXBBR8opSwCVqvia7j69Nn1w9O5zSt1b+lYhkr+mEncALWr4bONp82ALKKk5QuAuqJtM86qdFvMM6c2BmEe+9O7w3xD56wC1gHpi74/j8rW959amPXHvqVPPQ8WM0v9CjBjKDo62Bl8k17ypXtpZPZxENtzZo5cIzdOHiKn396c33fubM5n12XmUhLGhXa7K2qHa4ZmKVNwZme7vA3qj38czUEiW/8czgsRvOtz7RCpu/GjQaHAh5w0UEJJXktYKQkslQymHtCwUIU7LPhe5tOrZawRzGbhKuLHxqCYiBbM+m6A8ZU0Bp3H9m9ZPHF9pvajbDa4PAN2U1/oWBz1mBKhAgTW5XUnJFR8pEfFeK41Z7KSDtnHIPAnaQANjP801ADUwApx8X7umLW3+OYPb+RhNW4PtsCXADJgMskLIlc223vqQgJsdzZfMVcKaHB5TQc/iRz9G8JZMAPPDYxhcurPW/2L88oOlwSHGU6KYLXMAk8qqy7W+zWcKqdc1udLk6MBnmhUgA7cggsy+d3fzjrX5/OhqMKJqNeTc41bkbQpcY6yylIom4vaaI2EpC1z1+z80LN7+ACWBEwPSRlclTT1wafnQymfDWdZqmtlFqzL9kVQiuAVzfI9/zKAzdVrvlv/OFTkBB1gr+/vTFT24ORqfjJOW2mKjJVINhg9f8jXaXmt0etbrz1Gy3qOH71HCd17/ttkPNFzABjBiYRDmNHr80/Hie6S5TQZWUnPq8ICC/1aFwDsIvLVJ7aYnaKIGbCJqh5x7FI7e80AmobSEylcKZZXluG6OC052EhMoFoHGv2ebfCewsgIT5eWo1AiEk6oHn8OPQ8/PJgFnoSYnq1UR+ZkaYwkcJTn2KTJM07M6BAF05bpKnxjccAAIYiSNLYZvrtL1exsCngpRd8Tm+S34TcaHV1DXDsRe2C2yjVLUUZh1/BU8xfJAUilzPIy/wSTlqjojUQSCgFrJmwm1Xb4cV2HNmwLqF7SC7Snmak4PgAlRXomIhJYBRADUfMRE7F+zmngCsog6CBYhK1Lnp6e/yA2nl48uC+/5laX6ZoqhrXmEeBAJISFFyFrA9bh6tdLw/oAWvza/OZFnGFWNelCsHhoAir2JugDAJxgIw2J1gs79XcFvb7DskcUSTKDnDbB2EIJgW6Jhlac2/7JQXTATZ5ibAFWIap/wHGJPRiEajWXxua/rwQSGABtN0axZDvxG0m8S8AZLGsdE4rs3GYxoP+jTAdvkAPf2N4fTBr5wfX9AcHQgLeHxltDaZTsfjwZD/smM8HAIjmgwnNMZ5f3ODtlbXaBPY2OwX314Z/cXOxutzAUHP72fhV+4++dkTR5buWj60zH/dEaLak0Lwvv4EhGxubtL6+iZ9Z2X4J586vfpnRLQBjA5EHQCUl8fxv4fe4K4iL+DrEwqCgOugOLa/4DiclE+vTz78qTNrH7cryRSgA0PAg2f7n7pX0ivjJLujPxp1XMfl+jjJi9Fwlp1+YmN231e/O/j6jp5+SgfoEwAngJcDdwM/Dtxrx9cCrwFeCfwYcAjwADpIFpABkSVCAO7urXl7f2z9PqMD+AmAZeAk8GLgJXa8FjgO9K6g+QORBXZanrdrmVsBuUX9fBHwP6w5oUlUPapLAAAAAElFTkSuQmCC\" title=\"emoji-thumbsdown\"></p>\n<blockquote>\n<p>“The road to Hell is paved with good intentions.” - Disputed Authorship</p>\n</blockquote>\n<h2 id=\"Gatsby-to-the-Rescue--My-New-Site\"><a href=\"#Gatsby-to-the-Rescue--My-New-Site\" aria-label=\"Gatsby to the Rescue  My New Site permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gatsby to the Rescue! – My New Site</h2>\n<p>Once taking a full-time position, especially when you have a family full of children, time is of premium value. I just never had a need or desire to update my portfolio online. I figured if recruiters wanted to head-hunt me from my current job, they need to come with a good monetary offer, good benefits and companies will have to go off content I have produced. <strong>So Why Update My Site Now?</strong> <em>Am I looking for new work?</em> Yes, and No. </p>\n<p>I’m not actively seeking new employment, but I am looking for solutions for upcoming projects at work, but more importantly, I’m looking to give my side-business a boost by offering niche services. There is a market for helping small businesses get a site up and running on <code class=\"language-text\">Wordpress</code>, <code class=\"language-text\">Squarespace</code>, even <code class=\"language-text\">Wix</code>, but **I want to produce sites I like to build as well as sites optimized for the web of the future - speedy, SEO optimized, accessible, and PWA friendly. </p>\n<p>I started seeing devs I know tweeting about <code class=\"language-text\">Gatsby</code> so I checked it out and fell immediately in love. I have downloaded and configured a dozen or so starters, and I have started making open-source contributions to the <a href=\"https://github.com/gatsbyjs/gatsby\">Gatsby repo on Github</a>, but it is time to put something into prod, and refactoring my portfolio and adding a blog seemed like the perfect first candidate. <a href=\"https://twitter.com/WesleyLHandy\">Hit me up on twitter with feedback on the new site</a></p>\n<h2 id=\"My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\"><a href=\"#My-Plan-For-This-Blog--Or-Why-You-Should-Come-Back\" aria-label=\"My Plan For This Blog  Or Why You Should Come Back permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>My Plan For This Blog – Or Why You Should Come Back</h2>\n<p>After this introductory post, I plan to post on the following:</p>\n<ul>\n<li>Technical Post on How I Built This Site</li>\n<li>Series of Technical Posts on Coding Practices I&#x26;rsquove Learned During My First Two Years of Professional Development</li>\n<li>Series of Posts Giving Specific Details and Advice Concerning Transitioning Careers, or On Becoming a 2nd Career Dev</li>\n<li>Other Technical Posts as topics arise</li>\n</ul>","id":"698dced9-6847-5220-ab59-f3e554d5a4ff","timeToRead":2,"frontmatter":{"date":"2019-04-04","path":"/blog/hello-world.html","tags":["gatsby","intro","development"],"title":"My New Blog - What To Expect from Me?","featuredAlt":"Batman says code like a champion today","redirect_from":null}}]}}}}