<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Software Engineering - Rafael Quintanilha]]></title><description><![CDATA[Unsorted thoughts about software engineering, web development, quantitative analysis, financial markets, books and tradition.]]></description><link>https://www.rafaelquintanilha.com/</link><image><url>https://www.rafaelquintanilha.com/favicon.png</url><title>Software Engineering - Rafael Quintanilha</title><link>https://www.rafaelquintanilha.com/</link></image><generator>Ghost 5.79</generator><lastBuildDate>Thu, 22 Feb 2024 20:11:39 GMT</lastBuildDate><atom:link href="https://www.rafaelquintanilha.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[React Best Practices: How to Write Better React Apps]]></title><description><![CDATA[A summary of modern React best practices, with tips that can be applied to real-world applications.]]></description><link>https://www.rafaelquintanilha.com/react-best-practices-how-to-write-better-react-apps/</link><guid isPermaLink="false">6383c14a14168e003dd8f7a8</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[SEO]]></category><category><![CDATA[Best Practices]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 07 Sep 2022 19:58:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="what-is-react-and-why-use-it"><strong>What is React and why use it?</strong></h2><p>While web development isn&#x2019;t <em>new</em>, some aspects of it are. In particular, frontend engineering is somewhat of a new term. Back in the day, you would see &#x201C;web designers&#x201D; and &#x201C;webmasters&#x201D;, but rarely <em>frontend developers</em>.</p><p>There&#x2019;s a good reason for it - there was no need! Websites were simple, mostly static, and the bigger complexity was around designs, not functionality.</p><p>Needless to say, we are way past that now. Websites evolved into web apps, browsers became more powerful and the era of desktop applications is over, disrupted by the eruption of mobile devices. While it took some time for the consensus to establish in web apps and not in mobile apps, it seems to be fairly understandable now that web apps provide better availability, portability, and ease of use than native applications. And as mobile devices become more powerful, and optimizing for the web becomes a sexy engineering problem, the end result is an outburst of well-engineered, optimized, and resourceful applications right here, on the web.</p><p>But as we have learned from the history books, there&#x2019;s no power vacuum. The web was set to reign, but who shall be the king? Enter <a href="https://reactjs.org/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong><strong>React &#x2013; a JavaScript library for building user interfaces</strong></strong></strong></a>.</p><p>This library maintained by the fine folks at Facebook took the market share and ended once and for all the <strong><a href="https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong>JavaScript fatigue</strong></strong></a></strong>: that feeling everyone around in 2015 had. Every day a new frontend framework is competing for the top spot. Then eventually React appeared, people liked it, and the problem was settled.</p><p>This (not so) short introductory story is the answer to <em>what </em>React is and <em>why </em>you need it. Because React is a JavaScript library for the ever-growing frontend environment, you need it because it is popular, way maintained, liked, and used throughout the globe, in FAANGs and local shops. You can&#x2019;t go wrong choosing React.</p><h2 id="what-makes-react-hard-to-learn-for-beginners"><strong>What makes React hard to learn for beginners?</strong></h2><p>React doesn&#x2019;t have a particularly hard abstraction or technical conception. On the contrary, its single source of truth mantra has been a breeze for seasoned web developers.</p><p>However, this change in paradigm (for the better) can hit harder if you are used to using vanilla JavaScript or the last king, jQuery. Communication is rarely event-based, as opposed to what JavaScript typically enforces by design or with its backend counterpart, NodeJS.</p><p>Componentization is a concept that is easy to grasp but demands time to master. <strong><a href="https://buttercms.com/blog/learn-react-hooks-by-writing-your-first-hook/?ref=rafaelquintanilha.com"><strong><strong>Hooks brought the functional flavor</strong></strong></a></strong> that seems to be the current trend, despite component lifecycles that may be more familiar to Java developers.</p><p>In short, what makes React hard for beginners is that <em>it is React</em>, not an adaption, a fork of a known framework, or an abuse of the JavaScript language. It&#x2019;s a new paradigm, focused on User Interfaces, simplicity, and opinionated state management.</p><h2 id="react-best-practices"><strong>React best practices</strong></h2><p>Every language and framework has the so-called &#x201C;best practices&#x201D;, i.e., a community-accepted set of practices when using the tool. The following isn&#x2019;t an exhaustive list of them, but an attempt to list the ones that typically concern the average developer.</p><h2 id="security"><strong>Security</strong></h2><p>Every software engineer that had code shipped to production had to go over this drill. Is the code secure? Are there flaws? Are they exploitable? Given the architecture of the web, this matter is even more flagrant.</p><p>However, I&#x2019;d argue that React doesn&#x2019;t pose any special security threat that any web application doesn&#x2019;t have. Be aware of XSS attacks; store authentication tokens safely; sanitize HTML, and so forth.</p><h3 id="sanitize-html">Sanitize HTML</h3><p>By having its own <em>templating engine </em>that allows dynamic variables to be inserted into HTML, React exposes a security issue that every web developer should be aware of: injecting malicious code in HTML.</p><p>As the classical example goes, we don&#x2019;t want users to pass any kind of script that can be rendered on an HTML page. Because of that, there&#x2019;s a process called <em>sanitization</em>, where we allow only specific tags to be rendered on a page.</p><p>Imagine you have a CMS like ButterCMS and render the content generated by the content creator without any kind of filter. Well, <strong><strong><a href="https://reactjs.org/docs/dom-elements.html?ref=rafaelquintanilha.com#dangerouslysetinnerhtml" rel="follow noopener"><strong>React exposes the property <em>dangerouslySetInnerHTML</em></strong></a><em> </em></strong></strong>that serves this very purpose: get a raw HTML for an API, and render it in an element.</p><p>But the API isn&#x2019;t named like that for nothing. Suppose this content contains a valid script that collects user information and posts it back to the attacker database: you&#x2019;re essentially adding a trojan horse to your website!</p><p>In order to prevent such cases, you can use libraries like <strong><strong><a href="https://www.npmjs.com/package/sanitize-html?ref=rafaelquintanilha.com" rel="follow noopener"><strong>sanitize-html</strong></a></strong></strong> to allow only specific tags to be rendered. For example, if your goal is to render a blog post, you can allow only the traditional &lt;div&gt;, &lt;p&gt;, &lt;b&gt;, &lt;i&gt;, &lt;img&gt;, etc tags, and block suspicious ones like &lt;script&gt;.</p><h3 id="secure-apis">Secure APIs</h3><p>Although this isn&#x2019;t a problem specific to React, this is a common problem faced by any front-end developer. We typically need to connect to our brothers in blood, the backend engineers, who have carefully crafted an interface for us to communicate.</p><p>However, this API often is <em>secured</em>, meaning that you need proper credentials to access it. The authentication process occurs mostly in the backend but is the front-end&apos;s job to keep the access token safe and sound.</p><p>There is a lot of <strong><a href="https://stackoverflow.com/questions/3220660/local-storage-vs-cookies/3220802?ref=rafaelquintanilha.com#3220802" rel="follow noopener"><strong><strong>debate about whether you should store it in the Local Storage or in cookies</strong></strong></a></strong>, and this matter warrants a post in itself. But while this is a personal choice and both can be used under the right circumstances, I find it crucial that you, as a developer, understand what the tradeoffs of each solution are.</p><p>I have used both, and suggest using cookies if you can. They provide more security layers and control, and if used with a compatible library in the backend, like <strong><strong><a href="https://flask-jwt-extended.readthedocs.io/en/stable/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Python&#x2019;s Flask</strong></a></strong></strong>, the implementation is a breeze.</p><p>In any case, before judging your friend who stores a JWT in the Local Storage, try to understand where the flaw is. Saying &#x201C;if your app JavaScript is compromised you are screwed&#x201D; isn&#x2019;t really an argument; once you&#x2019;re compromised, well, you are screwed anyway. Understand your app&#x2019;s needs first, and the rest should come naturally.</p><h3 id="install-linters">Install linters</h3><p>I mentioned before how good practices are nothing more than a community set of accepted practices, but as you have probably thought, this is subjective and hard to enforce.</p><p>Linters come to the rescue. There are awesome linters that will encapsulate a set of JavaScript or React-oriented best practices and complain whenever you drift off. This is great for ending an argument &#x2013; people will often disagree on how to best handle a particular scenario. A linter, or a programmatic way to warn about an unexpected code usage, will act as the mighty judge, settling the matter once and for all (you need to agree on the linter first though).</p><p>Linters are also great for big teams, where many people touch a single file repeatedly. If everybody uses a linter, you cut off most of the inconsistencies, save development time and make reviewing code a breeze.</p><p>When coding, you shouldn&#x2019;t focus too much on aesthetics. Sure, they are nice. But the less you need to worry about it, the better. Let developers focus on what they like, namely, code.</p><h2 id="testing"><strong>Testing</strong></h2><p>Think about that: you are already a developer, why would you do something manually? Programmers of course thought about that, and resisting the temptation of overengineering, also agreed on writing code for testing their own code. Isn&#x2019;t it beautiful?</p><h3 id="leverage-react-debugging-utilities">Leverage React debugging utilities</h3><p>There are a set of React practices that are often neglected. <strong><strong><a href="https://reactjs.org/docs/error-boundaries.html?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Error Boundaries</strong></a></strong></strong> are one of them.</p><p>When developing React applications, an interface is typically composed of several components in a tree that can escalate quickly. For that reason, if there&#x2019;s an error in the application, it&#x2019;s common to be lost in the hierarchy of components.</p><p>Error Boundaries can help you by raising the red flag on the exact node that experienced the flaw. More modern frameworks like<strong><strong> </strong><a href="https://buttercms.com/blog/what-is-react-remix/?ref=rafaelquintanilha.com"><strong><strong>React Remix</strong></strong></a><strong> </strong></strong>leverage this concept to enhance user and developer experience. Give them a shot and caught the issues in the act.</p><p>Another way to add better-debugging tooling to your web app is to convert to TypeScript. Fortunately, TypeScript is widely adopted and integrated into the React ecosystem now. With TypeScript, you get top-notch auto-complete, caught errors on the act, and reduce runtime errors by leveraging features like type-checking. Pairing the typed JavaScript version with a good text editor like VSCode is a game changer for serious web development.</p><h3 id="invest-in-test-driven-development">Invest in test-driven development</h3><p>Beware when getting into the world of testing &#x2013; you risk becoming addicted to it. In fact, some people like it so much that they develop backward! First, they create the test, <em>then </em>they write the code.</p><p>While this coding style isn&#x2019;t for everyone, this is particularly interesting when developing a functional application or library. Suppose that you are working on a calculator. There are some well-defined cases that you want to handle, and it&#x2019;s just fair that you work from there: you start by checking that addition works, then you move to multiplication, and handle edge cases.</p><p>For more complex applications, <strong><a href="https://rafaelquintanilha.com/writing-tests-as-user-stories-in-react?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong>I suggest treating your tests as user stories</strong></strong></a></strong>. Suppose you are working on a feature that needs to do X, Y, and Z. They are valid, strict metrics that you will be testing against. Once you established all the roadblocks, traps, and edge cases, it becomes way easier to just sit down and do what you already know.</p><p>Don&#x2019;t know if this is for you? Well, <em>test</em> first, and then let me know (pun intended).</p><h3 id="install-react-testing-library">Install React Testing Library</h3><p>Everything I mentioned before about React taking over the power void can be applied to <strong><a href="https://testing-library.com/docs/react-testing-library/intro/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong>React Testing Library</strong></strong></a></strong> or RTL. Designed for React and later adapted to other frameworks, the Testing Library took over hacky approaches like Enzyme, where developers would spend more time fixing tests than actually testing their applications.</p><p>React Testing Library has a simple API, a big community, and good principles, and should be your go-to library when unit testing your code.</p><h3 id="configure-user-events">Configure user events</h3><p>One of the main advantages of React Testing Library is abstracting away user events in single lines of code. For example: what if a user presses a specific key? Or if they move their mouse out of the window? Or focus on an input?</p><p>All those are events that can happen in a real app and oftentimes have a direct impact on what should happen next. For example, you can assert that a bouncing modal pops up if the user tries to leave the screen (it&#x2019;s annoying but effective&#x2026; what are you gonna do?). <strong><strong><a href="https://github.com/testing-library/user-event?ref=rafaelquintanilha.com" rel="follow noopener"><strong>A clear and simple API like the user events API</strong></a></strong></strong> from RTL is all you need in order to test like <em>user stories.</em></p><h2 id="components"><strong>Components</strong></h2><p>The heart of React, components are the best friend of the frontend developer. They encapsulate logic, UI blocks, and functionality. But how should you approach designing them?</p><h3 id="keep-component-creation-to-a-minimum">Keep component creation to a minimum</h3><p>Component creation should be understood as building a LEGO. You design the parts and glue them together. You start small, where each part is focused on its own job. It&#x2019;s the UI equivalent to functional programming, where each function has a single purpose. In fact, components are functions! So the comparison holds even stronger.</p><p>When designing an interface, it&#x2019;s often useful to draw it on a piece of paper. Using the same principle as in the test-driven approach, you have a <em>component-driven approach</em>. Start by designing your interface and what constitutes each part of it &#x2013; maybe you have a side panel, a list of results in which every result has a call-to-action button&#x2026; design them as an architect would design a living room, and the rest will flow naturally.</p><h3 id="introduce-state">Introduce state</h3><p>Using React for building user interfaces is nice, but if they are <em>static </em>there is nothing really exciting about them. Or at least nothing our predecessors, web designers, wouldn&#x2019;t do with tools like Photoshop.</p><p>What transforms React into a really powerful library is its power to, well, <em>react </em>to users&apos; interactions. That&#x2019;s the heart and soul of frontend engineering &#x2013; develop a nice UI, sure, but what good is a sleek-looking UI that isn&apos;t easy to use?</p><p>What solution does React brings to the table? The app or component <em>state </em>will dictate how your UI should behave. For example, it can display an error message for invalid input, disable a button for an incomplete form, share context and variables across many parts of the app, count how many times you have performed an action, tell whether you should render a modal or not&#x2026; there are endless possibilities that are exactly the reason why frontend development is so exciting: the user input is a new dimension in your variable matrix.</p><p>A <em>stateful </em>component is a component that renders differently based on its state. An input component that renders an error message or is disabled is a good example. On the other hand, a <em>stateless </em>component is a plain static UI, but is still useful. Suppose you want to render your website footer. Instead of duplicating code left and right, you can develop it once and call it anywhere, pretty much like a function, generating one source of truth, best for maintainability and consistency.</p><h3 id="use-props-to-pass-data-to-a-children-component">Use Props to pass data to a children component</h3><p>Sometimes your component is not stateful but still depends on outside variables. Think about a template, for example. It has a recipe, a specific form, but with &#x201C;gaps&#x201D; that are dynamically filled (variables).</p><p>Properties, or props, are precisely a way to customize a component that should always behave the same but can accept different data. Think about your driving license: everyone has the same, they look the same, and their layout is the same, but the name, number, expiration date, and whatnot are different. Those are the props filling up the gaps.</p><p>In React, props are always passed from father to child. We saw already that componentization transforms your app into a huge tree of code, and the communication needs to be direct, and top-down (there are some exceptions like contexts, though).</p><p>While this can be annoying occasionally, it really gives predictability to your code. If a variable is such, it <em>must be </em>because it is like so in the parent. And hence you can trace back that value to its origin, helping to debug a lot.</p><p>I remember my old days working on CakePHP where I would spend hours trying to decipher where that variable had come from. It was hard because communication wasn&#x2019;t direct, top-down. It was buried somehow in contexts and controllers. Call it pragmatic, but it will make your life easier.</p><h3 id="use-different-component-patterns">Use different component patterns</h3><p>As always, there is never one single way to tackle a problem. Before hooks took off on the 16th version of React, there was a famous React pattern called <strong><strong><a href="https://reactjs.org/docs/higher-order-components.html?ref=rafaelquintanilha.com" rel="follow noopener"><strong>HOC, or Higher-Order Components</strong></a></strong></strong>.</p><p>In this pattern, you encapsulate a particular component with another one, like a sandwich. But this gives it superpowers, or in less exciting terms, new props for it to use. For example, you could wrap your component in a HOC that would monitor the screen size in order to pass to your child component the width and height as props.</p><p>In some sense, Higher-Order Components worked as <em>decorators</em>, injecting logic into a given component. As mentioned, though, React Hooks was a great breakthrough and replaced this behavior with a nicer, more reusable API. Hooks work similarly to plugins, where you call them in your component to get a specific behavior.</p><p>Also before hooks, React components would be class-based, bringing more of the objected-oriented world to the frontend community. They would provide lifecycle hooks instead, where you could act when a specific event occurred, like the component mounting, or a specific prop changing.</p><p>The React team replaced this paradigm with a new one, using hooks, called <strong><a href="https://reactjs.org/docs/hooks-effect.html?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong>useEffect</strong></strong></a></strong>. Now, you can monitor everything that makes a component re-render, the act of being updated because something in the tree changed. It&#x2019;s up to you to monitor and act accordingly to whatever state or prop change happened.</p><p>While more flexible, arguably some developers miss the straightness of <em>componentDidMount </em>or <em>componentWillUpdate</em>. If that&#x2019;s who you are, you should check class-based components.</p><h2 id="styling"><strong>Styling</strong></h2><p>A hot topic with a myriad of alternatives, styling a web app is never a consensus. Constructed on top of a controversial piece of technology, we shall explore how you can approach styling in your React applications.</p><h3 id="try-inline-css">Try inline CSS</h3><p>The simples solution, by and large, is to embrace tradition and use an inline style like everyone was doing with HTML in the 90s. There&#x2019;s nothing really wrong with it &#x2013; with the exception that is hard to reuse.</p><p>React will handle style pretty much like a JSON object, and this will be the source behind the multiple CSS-in-JS frameworks that emerged. In any case, inline CSS is good, simple, and efficient. They will lack performance improvements (like being able to cache a separate CSS file), and maybe software engineering best practices. But they will work just fine.</p><h3 id="import-styled-components-as-an-object">Import styled-components as an object</h3><p>Using JavaScript to style your components has the unbeatable advantage of being able to control the style dynamically. Suppose you are building a component that changes its color based on a given input. JavaScript and React will make your life a breeze because you can just conditionally use the input to render the desired color.</p><p>Of course, people wouldn&#x2019;t stop there: if you can use JavaScript in such cases, you can also use them to control other aspects of your styling. For example, font size, brand colors, default line height, etc. Using technology like <strong><a href="https://www.styled-components.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><strong>styled-components</strong></strong></a></strong> allows you to write CSS-in-JS while creating a hierarchy of values that programmers so often like.</p><p>And as I mentioned before, the <em>style </em>property is nothing more than a JSON object. So you can leverage JavaScript constants to build your style schema, inherit from it, and write your component&#x2019;s style as you would write code. Neat.</p><h3 id="abstract-style-components">Abstract style components</h3><p>Styles are good and a simple solution, but as a project grows it won&#x2019;t scale. Think about how many primary buttons you have in your application and you will know what I mean.</p><p>As I mentioned in the previous section, styled-components help you to create a basic structure and build from there, with basic properties being set as constants. You can then combine them and create more complex structures, like buttons, paragraphs, headers, heroes, inputs, and so on.</p><p>In fact, React creates the perfect ecosystem for you to design your own component library. Forget about Bootstrap, Semantic UI, and their peers &#x2013; with React, you please any designer you work with consistency and accuracy.</p><h3 id="use-css-and-sass-stylesheets">Use CSS and SASS stylesheets</h3><p>Everything I said thus far is great but some freaks insist on using plain old CSS files. Why? Well, I can tell (I&#x2019;m one of those freaks). CSS is a technique on its own, and I prefer the separation of concerns of having a file dedicated to styling. It&#x2019;s easier to review, change and adapt. Also, it can be cached when performance is at stake.</p><p>With the surge of frameworks that allow CSS Modules, the typical problem of classes clashing with each other is over. Plus, it generates a fingerprint that helps developers debug by targeting the precise component with that particular style.</p><p>And if you want the option to add parameters to your classes, like a brand color or semantic font size, SASS can help you. Pair both and you will get the best of two worlds, while still looking cool by using a time-tested fool-proof technology like cascading stylesheets.</p><h2 id="project-structure"><strong>Project structure</strong></h2><p>React is definitely not an opinionated library. As Uncle Ben would recall, &#x201C;with great powers come great responsibilities&#x201D;. I would also say, in a poetic tone, that you are free to do whatever you want, but a prisoner of the consequences.</p><p>With that in mind, let us take a look at how you can structure your React project.</p><h3 id="split-components-into-separate-tsx-files">Split components into separate .tsx files</h3><p>We already mentioned the power of componentization and treating components as you would treat functions in a functional paradigm. But in React this is even better if you enforce that only one component should exist per file.</p><p>First, files become smaller, and easier to tweak and review. Secondly, the <em>separation of concerns </em>buzzword rings again. By having a single file handling a single part, it&#x2019;s very easy to spot and tackle eventual changes. Finally, if working on a larger team, will reduce conflicts and make collaboration a breeze.</p><h3 id="give-each-component-single-responsibilities">Give each component single responsibilities</h3><p>I&#x2019;m a big fan of small, self-contained files, functions, and components. Think of them as small building blocks that are combined and used to create something bigger, like the pyramids, or a computer processor.</p><p>By assigning single responsibilities to each component, you are essentially functioning as a factory, with ultra-specialized employees that handle one thing and that thing only. Therefore, if <em>X </em>goes south, you know immediately that you need to talk with the one responsible for <em>X</em>. If each component has a single responsibility, it follows that it must exist only one component for it.</p><p>Combine multiple components with single responsibilities and you get your own production line.</p><h3 id="group-files-by-structures-or-routes">Group files by structures or routes</h3><p>We have already learned that React won&#x2019;t enforce any file structure. Some people will circumvent this freedom but enforcing their own strict rules. I disagree. I believe React is better experienced if you leverage this freedom.</p><p>I explain: a successful folder structure is one you don&#x2019;t need to think about. Frankly, the less you need to think about those petty things, the better. On that note, I like to group files <em>semantically</em>, or when they belong to a specific chunk of the app.</p><p>Have a route that renders a specific view? Add all your components there. Created a new page? Create also a new folder and add the corresponding components there as well. Simples structure. Not much thought is needed.</p><p>I oftentimes see people trying to be smart and breaking down components in multiple folders, with technical characteristics attached to them, like calling them <em>atomic</em>. I don&#x2019;t like it. This means creating a new file or folder is no longer a no-brainer, and should be actively reviewed at the expense of having inconsistent file structures across the board. If you don&#x2019;t care about the inconsistencies, then why create a rule in the first place? Moreover, you really don&#x2019;t gain much (if anything) by adding a custom file structure to your projects. Developers aren&#x2019;t supposed to be navigating in folders anyway. Components are small and self-contained, which means you potentially have a lot of files, so what&#x2019;s the use of manually looking for them? Hence my proposal: group files by routes or pages, and forget about it.</p><h3 id="avoid-too-much-nesting">Avoid too much nesting</h3><p>React is a big tree of components as discussed, and this is fine. However, if you are nesting too much, you probably are doing it wrong.</p><p>There are so many levels that you can descend. You have a list, a CRUD, a modal&#x2026; you can&#x2019;t nest forever. If possible, favor the horizontal spread of components, in its own routes, shallow enough that you are not lost in the abstraction and easy enough for a developer to find his or her way through the code.</p><h2 id="using-react-with-a-headless-cms"><strong>Using React with a headless CMS</strong></h2><p>React is a library for building user interfaces, as we have seen. But it has some interesting integrations. For example, you might want to have your app&#x2019;s content set somewhere else but render it in your shiny, fast, and efficient React app.</p><p>For such cases, content management systems like ButterCMS are a breeze. I spoke already about the separation of concerns, but this isn&#x2019;t only related to code. In fact, the more you can separate areas of expertise, leaving people to their bread and butter, the better.</p><p>If you have a team of content creators, you can give them the freedom to put their creativity to work, generating content that will later be consumed and rendered in your application. Your developers shouldn&#x2019;t need to have additional work if content changes &#x2013; the own project structure should be able to do it.</p><p>Connecting a CMS provider with a React framework like GatsbyJS will empower you to do exactly that &#x2013; <strong><strong><a href="https://buttercms.com/blog/leveraging-gatsby-incremental-builds/?ref=rafaelquintanilha.com"><strong>connect to the content being generated, listen to changes, and rebuild your site with fresh content</strong></a></strong></strong>.</p><p>Server-side rendering applications like NextJS will also be valuable by fetching data from the CMS and serving to the user as requested.</p><p>In short, the JavaScript ecosystem for content management has evolved to the point where having blazing-fast, <a href="https://buttercms.com/blog/react-seo-how-to-build-search-friendly-pages-in-react/?ref=rafaelquintanilha.com" rel="follow"><strong><strong><strong>SEO-friendly web apps</strong></strong></strong></a> can be achieved with both great content and developer experiences.</p>]]></content:encoded></item><item><title><![CDATA[How to incrementally migrate a Gatsby app to TypeScript]]></title><description><![CDATA[Learn how you can safely adopt TypeScript in your project, right now, without major changes.]]></description><link>https://www.rafaelquintanilha.com/how-to-incrementally-migrate-a-gatsby-app-to-typescript/</link><guid isPermaLink="false">6383829114168e003dd8f5b1</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 27 Jul 2022 15:43:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/how-to-incrementally-migrate-gatsby-app-typescript--1--1.png" class="kg-image" alt loading="lazy" width="730" height="487" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/how-to-incrementally-migrate-gatsby-app-typescript--1--1.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/how-to-incrementally-migrate-gatsby-app-typescript--1--1.png 730w" sizes="(min-width: 720px) 720px"><figcaption>Tips on how to migrate a Gatsby app to TypeScript</figcaption></figure><p>It shouldn&#x2019;t come as a surprise that TypeScript is getting more traction among developers by the day. Support for it has grown considerably, as well as the community and number of projects adopting this technology.</p><p>It wasn&#x2019;t always like that, though. Web developers have been burned before by hot technologies that disappeared, and it&#x2019;s only fair that some in the community are more skeptical about big changes. In fact, <a href="https://en.wikipedia.org/wiki/Lindy_effect?ref=rafaelquintanilha.com" rel="noopener">the Lindy effect</a> proposes that every day a piece of technology continues to survive, the longer it is expected to exist.</p><p>The goal of this article is not to convince you to migrate to TypeScript; I assume that if you are here, you have already been sold on the benefits of static typing in a dynamic language like JavaScript. However, if you are like me, you probably have been delaying the migration, fearful of the amount of work needed to set it in motion.</p><p>Well, fear no more! I&#x2019;ve done the heavy lifting for you. In this article, you will learn how to adopt TypeScript incrementally, so you can have a smooth transition and a good night of sleep after work.</p><h2 id="why-incrementally"><strong>Why incrementally?</strong></h2><p>Why do we have &#x201C;incrementally&#x201D; in the title of this article? Isn&#x2019;t that just delaying the inevitable? Why not perform a full migration at once?</p><p>Those are valid points, and in some cases, they can even be the most advisable. However, I am assuming you have a somewhat large project, big enough that using a codemod won&#x2019;t work (or will require too much workaround).</p><p>Or maybe you work on a specific part of an app in a larger team and want to run a pilot before doing the big change.</p><p>In all cases, there are valid scenarios where one would take the cautionary road first. And even though you will find a bunch of codemods or migration methods that claim to be seamless, the reality is that if your project has some complexity, it might not be as easy as they preach.</p><p>However, to offer a counterpoint, the folks at Stripe seem to disagree with me. They just recently published a <a href="https://stripe.com/blog/migrating-to-typescript?ref=rafaelquintanilha.com" rel="noopener">piece claiming to have migrated millions of lines of code to TypeScript.</a> If you are feeling adventurous, it&#x2019;s worth checking it out!</p><h2 id="how-to-set-up-typescript-in-an-existing-gatsby-app"><strong>How to set up TypeScript in an existing Gatsby app</strong></h2><p>Alright, for today&#x2019;s experiment we&#x2019;ll assume you already have a Gatsby app and want to perform a gradual migration.</p><p>Remember that if you are creating a new project today, Gatsby already supports TypeScript as the main language from the beginning. Unfortunately, that&#x2019;s not the case for most projects that were bootstrapped in older versions of Gatsby, so we are going to take a different route.</p><p>The Gatsby docs already present a <a href="https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/?ref=rafaelquintanilha.com#migrating-to-typescript" rel="noopener">good guide on how to migrate</a>. However, there are a few tweaks that we need to do in order to get it up and running smoothly.</p><h3 id="change-your-js-files-to-tsx"><strong>Change your .js files to .tsx</strong></h3><p>The easier part is to change all components you want to migrate to .tsx, or create new ones in this format. No work is needed on Gatsby&#x2019;s side for this to work! That&#x2019;s pretty neat.</p><h3 id="install-dependencies"><strong>Install dependencies</strong></h3><p>There are, however, some libraries to be installed. Make sure you add them to your <code>devDependencies</code>:</p><pre><code class="language-shell">$ npm i &#x2013;save-dev @types/node @types/react @types/react-dom typescript </code></pre><h3 id="generate-tsconfig"><strong>Generate <code>.tsconfig</code></strong></h3><p>TypeScript has a config file called <code>.tsconfig</code>, which is hugely customizable and will vary from project to project. However, there are some specific changes we need to make in order to allow TypeScript and JavaScript to coexist in harmony, as this is a requirement for everyone to adopt TS gradually.</p><p>An example of a working <code>.tsconfig</code> is as follows. Make sure to add it to the root folder of your project:</p><pre><code class="language-javascript">{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;es2016&quot;,
    &quot;jsx&quot;: &quot;react&quot;,
    &quot;module&quot;: &quot;commonjs&quot;,
    &quot;allowJs&quot;: true,
    &quot;outDir&quot;: &quot;./dist&quot;,
    &quot;esModuleInterop&quot;: true,
    &quot;forceConsistentCasingInFileNames&quot;: true,
    &quot;strict&quot;: true,
    &quot;skipLibCheck&quot;: true
  },
  &quot;exclude&quot;: [&quot;node_modules&quot;, &quot;public&quot;, &quot;.cache&quot;]
}</code></pre><p>You can also check an example <a href="https://github.com/rafaelquintanilha/gatsby-ts-vanilla-extract/blob/master/tsconfig.json?ref=rafaelquintanilha.com" rel="noopener">on this public repo in GitHub</a>.</p><p>Some of the needed configs are as follows:</p><ul><li>Add <code>&quot;jsx&quot;: &quot;react&quot; </code>to make sure the compiler knows we are in a React project</li><li>Set <code>allowJs: true</code>; once JavaScript and TypeScript need to coexist, this flag should be turned on</li><li>Add <code>outDir: &quot;./dist&quot;</code>, which makes VS Code happy and prevents unwanted errors</li></ul><h3 id="declaring-globals"><strong>Declaring globals</strong></h3><p>If you got this far, you already have most of your setup working. However, there are still some rough edges.</p><p>The most obvious is about CSS modules; Gatsby works with CSS modules by default and we need to let TypeScript be happy about it. If you use <a href="https://blog.logrocket.com/how-to-use-svgs-in-react/?ref=rafaelquintanilha.com" rel="noopener">SVGs as components as described here</a>, this will also be useful.</p><p>At the <code>src</code> folder of your project, create a file called <code>globals.d.ts</code> and add the following:</p><pre><code class="language-javascript">declare module &quot;*.module.css&quot;;
declare module &quot;*.module.scss&quot;;
declare module &quot;*.svg&quot; {
  const content: string;
  export default content;
}</code></pre><p>This will make sure that both CSS and SVG are <a href="https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html?ref=rafaelquintanilha.com" rel="noopener">treated and handled as modules</a>.</p><p>Again, you can check <a href="https://github.com/rafaelquintanilha/gatsby-ts-vanilla-extract/blob/master/src/globals.d.ts?ref=rafaelquintanilha.com" rel="noopener">a working example in GitHub</a>.</p><blockquote>If you are using ESLint, it may complain about .d.ts files. In this case, you can <a href="https://stackoverflow.com/questions/63238879/eslint-only-declares-and-type-imports-are-allowed-inside-declare-module/63239805?ref=rafaelquintanilha.com#63239805" rel="noopener">disable the linter in such extensions</a>.</blockquote><h2 id="typing-using-prop-types"><strong>Typing using prop types</strong></h2><p>One of the main advantages of TypeScript is to allow static typing in JavaScript. When developing with React, this is much welcomed, because it makes it harder for us to add non-existing props or even pass the wrong variable.</p><p>Before TypeScript was a thing, the React team popularized <a href="https://reactjs.org/docs/typechecking-with-proptypes.html?ref=rafaelquintanilha.com" rel="noopener">typechecking with prop types</a>.</p><p>Prop types were an intermediary step between no validation and strict typing. With prop types, developers could list all props in a given component, their corresponding type, and whether they are optional or mandatory.</p><p>For example, suppose we have a component that receives a prop called <code>magicNumber</code>, which of course should have the type number:</p><pre><code class="language-javascript">import PropTypes from &apos;prop-types&apos;

const MyComponent = ({ magicNumber }) =&gt; { &#x2026; } 

MyComponent.propTypes = {
  magicNumber: PropTypes.number.isRequired
} </code></pre><p>Suppose then that we render <code>MyComponent</code> but forget to pass <code>magicNumber</code> as prop, or pass a string instead. We would see a warning like this in the console, when in dev mode:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/warning-in-dev-mode.png" class="kg-image" alt loading="lazy" width="768" height="68" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/warning-in-dev-mode.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/warning-in-dev-mode.png 768w" sizes="(min-width: 720px) 720px"><figcaption>Warning in dev mode</figcaption></figure><p>However, there would be no static validation, and it&#x2019;s easy to overlook this kind of error in bigger components or larger projects. Also, we can add a prop but forget to set its type (there are some linters that help you with that though).</p><p>Using static typing, you can deprecate prop types in favor of regular TypeScript types:</p><pre><code class="language-javascript">type Props = {
  magicNumber: number
}

const MyComponent = ({ magicNumber }: Props) =&gt; { &#x2026; } </code></pre><p>Now, if you have a .tsx component that renders <code>MyComponent</code>, passing a prop with the wrong type will raise an error at build time:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/build-time-error--1-.png" class="kg-image" alt loading="lazy" width="730" height="208" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/build-time-error--1-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/build-time-error--1-.png 730w" sizes="(min-width: 720px) 720px"><figcaption>Build time error</figcaption></figure><p>And that&#x2019;s it! Safer, but less verbose, and comes with all typing benefits. All in all, prop types work but are less powerful than a robust typing strategy like TypeScript. If you want to get deeper on this subject, I recommend you read our preview article on the subject: <a href="https://blog.logrocket.com/comparing-typescript-and-proptypes-in-react-applications/?ref=rafaelquintanilha.com" rel="noopener">Comparing TypeScript and PropTypes in React applications</a>.</p><p>If you are convinced that static typing is superior to prop types, you should also know that there&#x2019;s a caveat when ditching prop types in a project that is a hybrid of TypeScript and JavaScript.</p><p>Suppose that we have a <code>WithTypeScript.tsx</code> component that renders the TypeScript version of <code>MyComponent</code>. If we try to pass <code>magicNumber=&quot;Hello World&quot;</code> this is going to raise an error once there&#x2019;s a type mismatch, as seen above.</p><p>However, if <code>WithTypeScript.tsx</code> receives <code>magicNumber</code> from a parent component written in pure JavaScript and passes it along to <code>MyComponent.tsx</code>, there is no way to validate if the variable is indeed a number. Once the parent component has no typing, no static error will be raised. And because there are no prop types in <code>MyComponent.tsx</code>, no runtime error will be raised. As such, this type mismatch won&#x2019;t be raised anywhere.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/no-runtime-error--1-.png" class="kg-image" alt loading="lazy" width="730" height="282" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/no-runtime-error--1-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/no-runtime-error--1-.png 730w" sizes="(min-width: 720px) 720px"><figcaption>No runtime error</figcaption></figure><p>Note how <code>IndexPage.js</code> calls a TypeScript component <code>WithTypeScript.tsx</code> with a wrong prop type. No warning is seen either in the editor or in the browser console.</p><p>Bear in mind that this only happens when .js and .tsx components are communicating, which will inevitably happen if you are gradually adopting TypeScript. Fortunately, there&#x2019;s a solution for it: we can have the best of both worlds by inferring types from prop types in TypeScript components. This way, we retain the prop types, but automatically convert them into types using the function <code>InferProps</code> from the <a href="https://www.npmjs.com/package/prop-types?ref=rafaelquintanilha.com" rel="noopener">prop-types</a> library.</p><p>This would be <code>MyComponent.tsx</code> combining types and prop types:</p><pre><code class="language-javascript">import React from &quot;react&quot;;
import PropTypes, { InferProps } from &quot;prop-types&quot;;

const Props = {
  magicNumber: PropTypes.number.isRequired,
};

type MyComponentTypes = InferProps&lt;typeof Props&gt;;

const MyComponent = ({ magicNumber }: MyComponentTypes) =&gt; { &#x2026; };

MyComponent.propTypes = Props;

export default MyComponent;</code></pre><p><a href="https://github.com/rafaelquintanilha/gatsby-ts-vanilla-extract/blob/master/src/components/ChildTypeScript.tsx?ref=rafaelquintanilha.com" rel="noopener">A full example can be seen here</a>.</p><p>The above solution will raise a static error at build time if there&#x2019;s a type mismatch but also raise a runtime error in the browser console if the wrong type is passed from a .js to a .ts component along the way. The drawback is that your code becomes more verbose.</p><p>However, if newer components only communicate with other .ts files, then it should be safe to ditch prop types. Eventually, when the migration is complete, you can completely remove them.</p><h2 id="conclusion"><strong>Conclusion</strong></h2><p>TypeScript is an exceptional tooling, but some developers refrain from adopting it in an existing codebase. This article aimed to elucidate how you can do it safely in your project, right now, without major changes.</p><p>While Gatsby in particular supports .tsx files out of the box, you need some workarounds to make your compiler happy considering typical approaches present in Gatsby codebases. Declaring globals for CSS Modules and SVGs are common pain points.</p><p>Finally, by having JavaScript communicating with TypeScript, we can&#x2019;t guarantee that some typing errors won&#x2019;t be opaque. Because of that, we can leverage the prop-types library and infer the types, getting the best of both worlds until we are safe to deprecate.</p><p>All code and examples present in this article can be found in <a href="https://github.com/rafaelquintanilha/gatsby-ts-vanilla-extract?ref=rafaelquintanilha.com" rel="noopener">this repo on GitHub</a>. Give it a try!</p>]]></content:encoded></item><item><title><![CDATA[What Is React Remix? Should It Be Your Next Framework?]]></title><description><![CDATA[Understand the pros and cons of adopting this new technology, with code examples.]]></description><link>https://www.rafaelquintanilha.com/what-is-react-remix-and-should-it-be-your-next-framework/</link><guid isPermaLink="false">6383878f14168e003dd8f608</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[Remix]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Thu, 24 Mar 2022 15:51:00 GMT</pubDate><content:encoded><![CDATA[<p>We&#x2019;ve all seen it happen before: something new becomes old until it eventually becomes new again. Trends appear, vanish, and come back again, maybe reinvented, probably with improvements, but the gist will be there. This is the wheel of life.</p><p>React <a href="https://remix.run/?ref=rafaelquintanilha.com" rel="follow"><strong>Remix</strong></a> is the &#x201C;back to basics&#x201D; strategy for web developers: a toast to the golden era (for some people) of web development&#x2014;where everything was HTML, and PHP provided the extra spice.</p><p>Whether people miss the HTML + PHP combo or not is debatable, but the principles behind it still stand, as we are going to see in a moment. <a href="https://buttercms.com/blog/react-seo-how-to-build-search-friendly-pages-in-react/?ref=rafaelquintanilha.com"><strong>I&#x2019;ve discussed at length</strong></a> the evolution of web development from static files, to dynamic content, then back to static plus dynamic. Now, React Remix is a new approach, revitalizing the quest for server-side generated content. In this article we will learn what Remix is trying to solve, how it is doing it, what are the consequences (good and bad) of the choices made, and, in the end, will create a small project to outline some of the principles discussed in practice.</p><h2 id="back-to-basics"><strong><strong><strong>Back to Basics</strong></strong></strong></h2><p>Let us understand how websites were created before, so we can better understand what React Remix is trying to solve. In the early days, web pages (nobody dared to call them &#x201C;applications&#x201D; back then) would be a collection of plain HTML. If data needed to change, developers would add a <em>form</em> that would be responsible for sending that data to the server.</p><p>Eventually, however, this data would need to be displayed. In order to do that, frameworks were created to allow developers to insert pieces of <em>dynamic </em>data into a <em>static </em>template. This way, users would have up-to-date information and developers would sleep tight at night without needing to manually refresh the content.</p><p>PHP was one of the go-to languages for this technique, and anyone who created websites up until the early 2010s probably had to deal with the infamous PHP tags in an HTML file, where dynamic content would be inserted after being read from an external source like a database or API.</p><p>However, things started to go south in PHP-land as developers started to praise a pattern called &#x201C;separation of concerns&#x201D;. Apparently, mixing PHP, HTML, JavaScript, and CSS in the same file became a burden at some point, and using PHP for templating lost its appeal, as other JavaScript frameworks like <a href="https://buttercms.com/blog/how-to-overcome-the-5-biggest-nodejs-mistakes/?ref=rafaelquintanilha.com" rel="follow"><strong>Node</strong></a> and React became more popular, and <a href="https://buttercms.com/blog/best-skills-for-junior-developers-job-success/?ref=rafaelquintanilha.com" rel="follow"><strong>new professions like front-end</strong></a> and back-end developer surged.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/seperation-of-concerns-diagram.webp" class="kg-image" alt loading="lazy" width="1201" height="629" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/seperation-of-concerns-diagram.webp 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/seperation-of-concerns-diagram.webp 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/seperation-of-concerns-diagram.webp 1201w" sizes="(min-width: 720px) 720px"><figcaption>Separation of Concerns</figcaption></figure><p>But the wheel of life (or should I say &#x201C;web development&#x201D;) spun and developers started to think that splitting a single page into multiple files is too cumbersome, and why not add <a href="https://buttercms.com/blog/how-to-take-your-css-to-the-next-level/?ref=rafaelquintanilha.com" rel="follow"><strong>CSS</strong></a>-in-JS and have loaders to load the dynamic information and actions to mutate data. And in this spirit, React Remix emerged.</p><p>In short, React Remix is a modern attempt&#x2014;using newer techniques and an opinionated framework&#x2014;to rescue the basics of web development. It is less dependent on JavaScript, semantically groups code, and prioritizes performance.</p><h2 id="is-it-really-necessary"><strong><strong>I<strong>s it really necessary?</strong></strong></strong></h2><p>A fair question is if we really need to make this U-turn pattern-wise, especially now that React has conquered its space as the frontend framework king. Here it&#x2019;s important to know that React Remix, if you haven&#x2019;t noticed yet, is built on top of React and therefore not a total disruption of the current patterns.</p><p>However, it does change some paradigms as we are going to explore further in a moment. But while React is an unopinionated frontend-only library, React Remix (as other competitors like <a href="https://nextjs.org/?ref=rafaelquintanilha.com" rel="follow"><strong>Next.js</strong></a> and <a href="https://www.gatsbyjs.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby</strong></a>) aims to bring React to the server-side rendering (SSR) realm, and therefore it needs to be analyzed under the assumption that this is something that you want.</p><p>In other words, React Remix helps developers who want the benefits of server-side rendering. React started as the &#x201C;V&#x201D; of the MVC (Model-View-Controller). React Remix is the whole package, reshaped as an evolution of the old ASP.net and PHP frameworks.</p><p>For a more formal definition, according to <a href="https://bejamas.io/blog/guide-to-remix-framework/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Bejamas</strong></a>, Remix is a server-side rendering JavaScript framework built on React that allows us to build full-stack web applications due to its frontend and server-side capabilities.</p><h2 id="why-pick-react-remix"><strong><strong><strong>Why pick React Remix?</strong></strong></strong></h2><p>We already discussed how React Remix is different from a plain React application. But as a developer, why would you decide to pick React Remix for your next project over another framework?</p><p>Here it&#x2019;s important to say that if all you are looking for is SSR, there are senior frameworks such as Next.js and Gatsby on the block. And if what you need is <a href="https://buttercms.com/blog/6-of-the-best-static-site-generators-in-2020/?ref=rafaelquintanilha.com" rel="follow"><strong>static site generation</strong></a> (SSG), then React Remix is probably not for you.</p><h3 id="ssr-vs-ssg">SSR vs SSG</h3><p>Right, but what the heck are all those acronyms anyway? I won&#x2019;t go too deep, but SSR stands for <a href="https://buttercms.com/blog/leveraging-gatsby-incremental-builds?ref=rafaelquintanilha.com#server-side-components/" rel="follow"><strong>server-side rendering</strong></a>, whereas SSG means static site generation. Both are alternatives to SPAs, or single-page applications, which React is by default.</p><p>In SSR applications, pages are templated like PHP in the golden days, and upon request, fresher information is inserted &#x2013; or in more technical terms, data is added at <em>run time</em>. SSG, however, fills the templates at <em>build time</em>, i.e., when the HTML page is being generated. By doing that, delivery time becomes way faster, although you need to spend more time building your application.</p><p>Which approach to choose will depend on your requirements, but as of today, I&#x2019;d argue that Remix won&#x2019;t probably be a fit for SSG applications, but is a contender for SSR. But does it win the contest?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/ssr-vs-ssg.webp" class="kg-image" alt loading="lazy" width="1201" height="629" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/ssr-vs-ssg.webp 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/ssr-vs-ssg.webp 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/ssr-vs-ssg.webp 1201w" sizes="(min-width: 720px) 720px"><figcaption>SSR vs SSG</figcaption></figure><p>As always, it depends. Bear in mind that the framework is very new and subject to change, and also that it tries to do <em>less things </em>and therefore you can eventually hit a roadblock. But if you have a defined scope and a clear understanding of your requirements, by all means, give it a shot. It has some fun paradigms, as we are going to see.</p><h2 id="react-remix-key-features-benefits"><strong><strong><strong>React Remix key features &amp; benefits</strong></strong></strong></h2><p>Alright, up until now we have discussed what React Remix is and what it tries to solve from a conceptual standpoint. It&#x2019;s time for us to understand what all this fuss means <em>in practice</em>, and later, to see some code in action.</p><h3 id="nested-routes">Nested Routes</h3><p>The creators of React Remix were also the minds behind <a href="https://reactrouter.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>react-router</strong></a>, a well-known library for routing applications. Remix has a very clever scheme of nested routes where you can compose routes pretty much like you can compose components. This is very convenient for the traditional &#x201C;list-view&#x201D; application, where you select an item of a list in order to inspect its details.</p><h3 id="error-boundaries">Error Boundaries</h3><p>It has happened to all of us &#x2013; a web application tries to load, something goes south, and the whole page crashes. React Remix argues it doesn&#x2019;t need to be this way. Would you short-circuit the whole component if a child breaks? Then why do that in your application? With <a href="https://remix.run/docs/en/v1/guides/errors?ref=rafaelquintanilha.com#nested-error-boundaries" rel="follow noopener"><strong>Error Boundaries</strong></a>, you have localized points of failure, so you don&#x2019;t disrupt the functioning of your app because only one thing went wrong.</p><h3 id="loaders">Loaders</h3><p>Static sites became dynamic for a reason, and that was because static is boring. However, fetching all data dynamically compromises your app&#x2019;s performance, impacts SEO, and so on. Remember how SSR websites fill the gaps (the templates) at <em>run time</em>? React Remix makes this work by using <em>loaders</em>, special functions that load the dynamic information from somewhere (a database, an <a href="https://buttercms.com/blog/webhook-vs-api-whats-the-difference/?ref=rafaelquintanilha.com#what-is-an-api/" rel="follow noopener"><strong>API</strong></a>) when the page is served. Loaders are added in your route file, so you know exactly what information is being retrieved at the time. A handy <code>useLoaderData</code><em> </em>hook is provided, so your component is shielded from the extra complexity.</p><h3 id="actions">Actions</h3><p>Actions are the hyperactive brothers of loaders, the ones responsible for <em>mutating data</em>. We give the name of &#x201C;mutation&#x201D; to every action that changes data, like inserting, editing, or deleting. Like loaders, you can add an action function in your Remix routes in order to intercept <em>form </em>data, and handle them as you please.</p><h3 id="javascript-free-zone">JavaScript-free zone</h3><p>Because actions are HTML forms and Remix can handle loading states for you, JavaScript becomes henceforth a luxury. That means that you can have a modern framework, using the latest technologies, and still be resilient to JavaScript not being available. In an era of JavaScript abuse, it is truly remarkable.</p><h3 id="full-stack-framework">Full-stack framework</h3><p>React Remix does an awesome job in closing the gap between frontend and backend, to the point that it becomes really fuzzy where one ends and the other starts. This has drawbacks, but also great advantages. Your codebase is unique, code is relatively grouped together, and development is smooth.</p><h2 id="criticism-of-react-remix"><strong><strong><strong>Criticism of React Remix</strong></strong></strong></h2><p>React Remix is an opinionated framework and, as such, has benefits and drawbacks. Although drawbacks can be objective or subjective, some points are not debatable. For example, the fact that Remix doesn&#x2019;t support SSG out-of-the-box and therefore shouldn&#x2019;t be used if that&#x2019;s your primary goal. However, because this is an opinionated article, I&#x2019;ll lay down what I think are the crucial points when deciding whether React Remix is the right tool for the job.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/react-remix-criticisim-positive-negative.webp" class="kg-image" alt loading="lazy" width="1201" height="629" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/react-remix-criticisim-positive-negative.webp 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/react-remix-criticisim-positive-negative.webp 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/react-remix-criticisim-positive-negative.webp 1201w" sizes="(min-width: 720px) 720px"><figcaption>React Remix criticism</figcaption></figure><h3 id="nested-routes-for-whom">Nested routes for whom?</h3><p>Let&#x2019;s be honest: nested routes are nice, but do you really need them? How many times are they useful enough that it warrants the choice? Granted, being able to preload chunks of your app is a nice addition, but you need to think if this is a feature applicable to your application.</p><h3 id="do-you-need-error-boundaries">Do you need Error Boundaries?</h3><p>It is nice that your app doesn&#x2019;t explode when a tiny chunk fails, but the question is: how often does a tiny chunk fail and your user is still able to pull some value out of it? It&#x2019;s definitely important in critical parts of your app, but let&#x2019;s face it, most of the time when something fails on a web page, the whole thing will need to be refreshed.</p><h3 id="not-very-restful">Not very RESTful</h3><p>If you come from a RESTful framework like Express, you probably will be a bit shocked that traditional verbs like PUT, PATCH, and DELETE are not encouraged. That&#x2019;s because HTML forms only support GET and POST verbs, and therefore you lose a bit of Remix&#x2019;s magic by using them (and it looks a bit hacky anyway). Personally, I think this is one of the main disadvantages, as it goes against API development best practices.</p><h3 id="do-you-really-i-mean-really-expect-to-be-functional-without-javascript">Do you really (I mean, really) expect to be functional without JavaScript?</h3><p>Oftentimes I see people bragging that they browse the web with JavaScript disabled and can&#x2019;t help but wonder from what planet they come from. Jokes aside, do you really want to account for those freaks extra sensitive people?</p><p>I understand the argument that too much JavaScript is bad, and often unnecessary, but <em>zero </em>seems a bit drastic to me. If that&#x2019;s not a must for you, probably all the &#x201C;we work without JavaScript&#x201D; propaganda won&#x2019;t make a difference for you anyway.</p><h3 id="rip-separation-of-concerns">RIP Separation of Concerns</h3><p>I&#x2019;m old enough to remember people praising &#x201C;<a href="https://dev.to/suspir0n/soc-separation-of-concerns-5ak7?ref=rafaelquintanilha.com" rel="follow noopener"><strong>separation of concerns</strong></a>&#x201D; as some sort of holy grail of web development. You have small, self-contained files, each doing its own job, like bees in a beehive. What&#x2019;s so wrong with that? If you are like me and like everything in its own file, React Remix may not be for you.</p><h3 id="css-is-cumbersome">CSS is cumbersome</h3><p><a href="https://remix.run/docs/en/v1/guides/styling?ref=rafaelquintanilha.com" rel="follow noopener"><strong>The approach for styling used in Remix</strong></a> is a bit odd, but not unexpected (remember we post requests using a form). In their API, you need to add a <code>&lt;link&gt;</code> tag, as you typically do with HTML. One of the benefits is that you can &#x201C;control your network tab&#x201D; and improve performance by importing only the required CSS in the most efficient manner. I then reply: do you want to control your network tab?</p><p>Also, your favorite CSS framework might not be supported just yet. Be mindful of that before you migrate all your codebase.</p><h2 id="react-remix-in-practice"><strong><strong><strong>React Remix in practice</strong></strong></strong></h2><p>The time has come for us to quit the babble and start what is really important: the code. The goal here is not to go in-depth on all React Remix features, but rather to provide a brief overview of the features discussed so far.</p><p>To achieve that, we are going to build a simple app called <a href="https://github.com/rafaelquintanilha/remix-lotr?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Remix LotR</strong></a> (code available in GitHub), leveraging this awesome <a href="https://the-one-api.dev/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Lord of the Rings API</strong></a>. I chose this example because it is (arguably) not only fun but also helps us understand some of the fundamentals of the framework. I hope that by using this project as a starting point, you can continue your React Remix studies and decide whether it is the right framework for you.</p><h3 id="one-remix-app-to-rule-them-all">One Remix app to rule them all</h3><p>If you want to follow along with this tutorial, head over to the LotR API website and claim your key. There are some rate limits but it should be more than enough for our project.</p><p>Also, make sure that you have React Remix set up and a new project created as described in their <a href="https://remix.run/docs/en/v1/tutorials/blog?ref=rafaelquintanilha.com#quickstart" rel="follow noopener"><strong>Quickstart guide.</strong></a> To make things simple, select <em>when prompted since deploying is out of the scope of today&#x2019;s project.</em></p><p>We will build a tree-view-like app where the Lord of the Rings characters will be listed and, upon selection, their details will show up. When a character is &#x201C;opened&#x201D;, you will also be able to load their quotes (if any). Although a bit silly, this is a clear way to understand how nested routes work and how you can use loaders to serve data to the client.</p><h3 id="your-first-route">Your first route</h3><p>If you have already created a Remix project, you will see the framework has created some boilerplate for us. The most important piece is the folder <em>app/routes, </em>where all pages live. Open <strong><strong>index.jsx</strong></strong> and add a <code>Link</code> to the page we are going to create soon.</p><pre><code class="language-javascript">import { Link } from &quot;remix&quot;;

export default function Index() {
  return (
    &lt;div style={{ fontFamily: &quot;system-ui, sans-serif&quot;, lineHeight: &quot;1.4&quot; }}&gt;
      &lt;h1&gt;Welcome to Remix!&lt;/h1&gt;
      &lt;ul&gt;
        {/* code */}
        &lt;li&gt;
          &lt;Link to=&quot;/characters&quot;&gt;Characters&lt;/Link&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><p>The highlighted portion is what we need to add. Feel free to remove the rest if you want. For now, the important piece is that, when linking to an <em>internal page</em>, we need to import the <code>Link</code> component from <code>remix</code>. This is important because this way Remix can preload the next route and improve your app&#x2019;s performance.</p><p>Alright, we added a link but the route doesn&#x2019;t exist yet. Let&#x2019;s fix this by creating a file <strong><strong>characters.jsx</strong></strong> in <strong><strong><em>app/routes</em></strong></strong>. This should be enough for now:</p><pre><code class="language-javascript">export default function Characters() {
  return (
    &lt;main&gt;
      &lt;h1&gt;Characters&lt;/h1&gt;
    &lt;/main&gt;
  );
}</code></pre><p>Save your work, then start the server by running <code>npm run dev</code> and notice that the link works. Congratulations, you have created your first route from scratch!</p><h3 id="listing-all-characters">Listing all characters</h3><p>Our app is rather lame so far. Fear not, we are going to spice things up a little right now.</p><p>The goal of this page is to list all characters in the Lord of the Rings series as cataloged by the API. Looking at the docs, you see that the <strong><strong><em>/characters</em></strong></strong> endpoint is what we want.</p><p>The way React Remix adopts to <em>load </em>data into a route is called&#x2026; well, <em>loaders</em>. You can easily test it by adding a function called <em>loader </em>in the route:</p><pre><code class="language-javascript">import { useLoaderData } from &quot;remix&quot;;

export const loader = async () =&gt; {
  const data = [&#x201C;Gandalf&#x201D;, &#x201C;Frodo&#x201D;, &#x201C;Aragorn&#x201D;];
  return data;
};

export default function Characters() {
  const data = useLoaderData();
  console.log(data);
  return (
    &lt;main&gt;
      &lt;h1&gt;Characters&lt;/h1&gt;
    &lt;/main&gt;
  );
}</code></pre><p>Add the highlight pieces and check how the data variable defined inside the loader function becomes available in the route component through the <code>useLoaderDat</code>a hook. This is one of the magical things about Remix: the data source and the actual component using it are coupled together.</p><p>Now, let&#x2019;s scrap the dummy data and actually make the API connection. For that, make sure you have the API key and the base path set. In order to make things cleaner, create a <strong><strong>.env</strong></strong> file at the root and add the following data:</p><pre><code class="language-c">BASE_PATH=&quot;insert API base path&quot;
API_KEY=&quot;insert an API key from https://the-one-api.dev/&quot;
</code></pre><p>Now you will be able to safely use the variables using <code>process.env</code>. Cool, right?</p><p>Let&#x2019;s then get back to the loader function and hook it properly:</p><pre><code class="language-javascript">export const loader = async () =&gt; {
  const response = await fetch(
    `${process.env.BASE_PATH}/character?sort=name:asc`,
    {
      headers: {
        Authorization: `Bearer ${process.env.API_KEY}`,
      },
    }
  );
  const data = await response.json();
  return data;
};
</code></pre><p>And that&#x2019;s it! Check how the actual data is available in your route component.</p><h3 id="adding-a-nested-route">Adding a nested route</h3><p>Everything is going according to the plan. Now, we want a character&#x2019;s details to be expanded by clicking on their name. Notice that the route right now is <strong><strong><em>/characters</em></strong></strong> so we&#x2019;ll need a nested route in the format <strong><strong><em>/characters/$id</em></strong></strong>.</p><p>Let us then get back to <strong><strong><em>characters.jsx </em></strong></strong>and link them properly:</p><pre><code class="language-javascript">import { useState } from &quot;react&quot;;
import { Link, Outlet, useLoaderData } from &quot;remix&quot;;

export const loader = async () =&gt; {
  /* code */
};

export default function Characters() {
  const data = useLoaderData();
  const [filter, setFilter] = useState(&quot;&quot;);
  return (
    &lt;main&gt;
      &lt;h1&gt;Characters&lt;/h1&gt;
      &lt;hr /&gt;
      &lt;div style={{ display: &quot;flex&quot;, marginTop: &quot;40px&quot; }}&gt;
        &lt;div&gt;
          &lt;label&gt;
            &lt;strong&gt;Filter:&lt;/strong&gt;
          &lt;/label&gt;
          &amp;nbsp;
          &lt;input value={filter} onChange={(e) =&gt; setFilter(e.target.value)} /&gt;
          &lt;ul&gt;
            {data.docs
              .filter((d) =&gt;
                filter === &quot;&quot;
                  ? true
                  : d.name.toLowerCase().includes(filter.toLowerCase())
              )
              .map((d) =&gt; (
                &lt;Link key={d._id} to={d._id} style={{ display: &quot;block&quot; }}&gt;
                  {d.name}
                &lt;/Link&gt;
              ))}
          &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div
          style={{
            position: &quot;sticky&quot;,
            top: &quot;20px&quot;,
            marginLeft: &quot;20px&quot;,
            alignSelf: &quot;flex-start&quot;,
          }}
        &gt;
          &lt;Outlet /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  );
}</code></pre><p>We added a client-side filter to help while looking for a specific character. Notice how it&#x2019;s React plain and simple. Also, we added a <code>Link</code> component for every character, using the variable <code>_id</code> as an identifier. The <code>Outlet</code> component is what houses the nested component that will be created next.</p><p>We can interpret routes&#x2019; chunks as variables as long as we prefix them with a <strong><strong>$</strong></strong>. That&#x2019;s what we are going to do now &#x2013; create a new folder <strong><strong><em>/app/routes/characters </em></strong></strong>and inside it a file <strong><strong><em>$id.jsx</em></strong></strong>. This will be enough for Remix to understand that a route like <strong><strong><em>/characters/123 </em></strong></strong>will expose a variable called <code>id</code> whose value will be <code>123</code>.</p><p>Open <strong><strong>$id.jsx</strong></strong> and add the following:</p><pre><code class="language-javascript">import { useLoaderData } from &quot;remix&quot;;

export const loader = async ({ params: { id } }) =&gt; {
  const response = await fetch(`${process.env.BASE_PATH}/character/${id}`, {
    headers: {
      Authorization: `Bearer ${process.env.API_KEY}`,
    },
  });
  const data = await response.json();
  return data;
};

export default function Character() {
  const data = useLoaderData();
  const character = data.docs[0];
  return (
    &lt;div style={{ display: &quot;flex&quot; }}&gt;
      &lt;div style={{ minWidth: &quot;300px&quot; }}&gt;
        &lt;h1&gt;{character.name}&lt;/h1&gt;
        &lt;div&gt;
          &lt;b&gt;Birth&lt;/b&gt;: {character.birth}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Death&lt;/b&gt;: {character.death}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Gender&lt;/b&gt;: {character.gender}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Hair&lt;/b&gt;: {character.hair}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Height&lt;/b&gt;: {character.height}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Race&lt;/b&gt;: {character.race}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Realm&lt;/b&gt;: {character.realm}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;b&gt;Spouse&lt;/b&gt;: {character.spouse}
        &lt;/div&gt;
        &lt;div&gt;
          &lt;a href={character.wikiUrl}&gt;Wiki URL&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Notice how we destructured <code>{ params: { id } }</code> in order to have access to the id <em>in the server</em>. Then, we used the API the same way as before to get the details, and <code>useLoaderData</code> again to access them in the component. Note that because <code>wikiUrl</code><code> </code>is an <em>external link</em>, we didn&#x2019;t use the <code>Link</code> component but rather a plain old anchor tag.</p><p>Play a bit with what we have right now. Notice how clicking on a character name instantly opens their details, and how hitting back in the browser changes the URL and also the content. This is the magic of nesting routes, rendered from the <code>Outlet</code> component.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/characters.png" class="kg-image" alt loading="lazy" width="770" height="484" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/characters.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/characters.png 770w" sizes="(min-width: 720px) 720px"><figcaption>Filtering characters</figcaption></figure><h3 id="how-much-nesting-is-too-much-nesting">How much nesting is too much nesting?</h3><p>Let&#x2019;s explore a bit further by adding <em>another </em>nesting level. Is that even possible? Of course, it is! And the good news is that there&#x2019;s nothing new to us.</p><p>The next goal is to create a link that will open the quotes for a given character. The route will be <strong><strong><em>/characters/123/quotes </em></strong></strong>and this suggests that we follow the same pattern as before: create a folder with the name of the parent route (in this case <strong><strong>app/routes/characters/$id</strong></strong>) and inside a file with the name of the desired route: <strong><strong><em>quotes.jsx</em></strong></strong>.</p><p>Open <strong><strong><em>quotes.jsx </em></strong></strong>and add the following:</p><pre><code class="language-javascript">import { useLoaderData } from &quot;remix&quot;;

export const loader = async ({ params: { id } }) =&gt; {
  const response = await fetch(
    `${process.env.BASE_PATH}/character/${id}/quote`,
    {
      headers: {
        Authorization: `Bearer ${process.env.API_KEY}`,
      },
    }
  );
  const data = await response.json();
  return data;
};

export default function Character() {
  const data = useLoaderData();
  return (
    &lt;div&gt;
      &lt;h3&gt;Quotes&lt;/h3&gt;
      {data.docs.length &gt; 0 ? (
        &lt;ul&gt;
          {data.docs.map((q) =&gt; (
            &lt;li key={q._id}&gt;{q.dialog}&lt;/li&gt;
          ))}
        &lt;/ul&gt;
      ) : (
        &lt;div&gt;No quotes found.&lt;/div&gt;
      )}
    &lt;/div&gt;
  );
}</code></pre><p>Alright! Nothing new to see here. Go back to <strong><strong>$id.jsx</strong></strong> and add the missing link:</p><pre><code class="language-javascript">import { useLoaderData, Link } from &quot;remix&quot;;

export const loader = async ({ params: { id } }) =&gt; {
  {/* code */}
};

export default function Character() {
        {/* code */}
        &lt;div style={{ marginTop: &quot;20px&quot; }}&gt;
          &lt;Link to=&quot;quotes&quot;&gt;See quotes&lt;/Link&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Save your work, click on the Link, and&#x2026; something&#x2019;s off. Nothing is showing up!</p><p>Why is that happening? Well, every time we want to make a <em>nested </em>route, we need to use the <code>Outlet</code> component. And as you can see, a single <code>Outlet</code> component is not enough &#x2013; you need one for each desired nested level.</p><p>Let&#x2019;s fix the issue by adding another Outlet component, this time in <strong><strong>$id.jsx</strong></strong>:</p><pre><code class="language-javascript">import { useLoaderData, Link, Outlet } from &quot;remix&quot;;

export const loader = async ({ params: { id } }) =&gt; {
  {/* code */}
};

export default function Character() {
      {/* code */}
      &lt;div
        style={{
          position: &quot;sticky&quot;,
          top: &quot;20px&quot;,
          marginLeft: &quot;20px&quot;,
          alignSelf: &quot;flex-start&quot;,
        }}
      &gt;
        &lt;Outlet /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Try again and see how it works!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/nested-characters--1-.png" class="kg-image" alt loading="lazy" width="1022" height="1178" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/nested-characters--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/nested-characters--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/nested-characters--1-.png 1022w" sizes="(min-width: 720px) 720px"><figcaption>Nested characters</figcaption></figure><h3 id="error-boundaries-in-action">Error boundaries in action</h3><p>The last thing that I&#x2019;d like to go over today is called <em>Error Boundaries. </em>Simply put, if something breaks in your app, the closest boundary will &#x201C;intercept&#x201D; it, preventing a deeply nested mistake from bubbling up the whole application. Once we are talking about a two-level nested route, it&#x2019;s important that we prevent an issue in the <em>quotes </em>route, for example, from blowing up the whole experience.</p><p>Let&#x2019;s test it by adding a function called <em>ErrorBoundary </em>and by simulating an error in our code:</p><pre><code class="language-javascript">import { useLoaderData } from &quot;remix&quot;;

export const loader = async ({ params: { id } }) =&gt; {
  const response = await fetch(
    `${process.env.BASE_PATH}/character/${id}/quote`,
    {
      headers: {
        Authorization: `Bearer ${process.env.API_KEY}`,
      },
    }
  );
  const data = await response.json();
  return data / 1000; // Generate some random error
};

export default function Character() {
  {/* code */}
}

export function ErrorBoundary({ error }) {
  console.error(error);
  return (
    &lt;div style={{ color: &quot;red&quot; }}&gt;
      Something went wrong: &lt;strong&gt;{error.message}&lt;/strong&gt;
    &lt;/div&gt;
  );

}</code></pre><p>Now, select a character, click on &#x201C;See quotes&#x201D;, and check how only the quotes part is broken.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/character-error-boundaries--1-.png" class="kg-image" alt loading="lazy" width="1018" height="460" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/character-error-boundaries--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/character-error-boundaries--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/character-error-boundaries--1-.png 1018w" sizes="(min-width: 720px) 720px"><figcaption>Error boundaries in action</figcaption></figure><h2 id="conclusion"><strong><strong><strong>Conclusion</strong></strong></strong></h2><p>React Remix is definitely an interesting framework and a new paradigm, at least for modern standards. It brings back some old web development principles, which is by no means a bad thing.</p><p>That said, the technology is fairly new and things are subject to change. Therefore, I&#x2019;d be cautious in adopting this stack in production. Nonetheless, it&#x2019;s worth keeping an eye on it and how it will develop in the future.</p><p>One more quick thing to note, being an SSR framework Remix isn&#x2019;t an ideal choice for a production app like ours. This is because every page hit will ping the API again, with data that won&#x2019;t change often, and therefore stress the API server unnecessarily (on the peril of being rate-limited). An SSG framework like Gatsby or Next would probably be a better choice. However, had our data been more dynamic (a stock price, for example), this approach would work better. Thus understanding the business needs of your app is crucial when determining whether React Remix is adequate for you.</p>]]></content:encoded></item><item><title><![CDATA[Leveraging Gatsby Incremental Builds With ButterCMS]]></title><description><![CDATA[Learn how to speed up your static builds with code examples.]]></description><link>https://www.rafaelquintanilha.com/leveraging-gatsby-incremental-builds-with-buttercms/</link><guid isPermaLink="false">63838a7b14168e003dd8f663</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[ButterCMS]]></category><category><![CDATA[Netlify]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 08 Dec 2021 18:08:00 GMT</pubDate><content:encoded><![CDATA[<p>In the first days of the web, all pages were <a href="https://buttercms.com/blog/what-is-a-static-site/?ref=rafaelquintanilha.com" rel="follow"><strong><em>static</em></strong></a>. This meant that a typical communication between a client and a server happened just once when the user first loaded the page. At that time, all resources were fetched and the content was rendered to the screen. If later the user came back to the same page, as long as the content hadn&#x2019;t changed, they would get the same result.</p><p>As time went on, the need for <em>dynamic </em>content became more apparent. For example, if I were at a <a href="https://buttercms.com/blog/using-zapier-zeit-and-buttercms-to-generate-a-news-aggregator-site/?ref=rafaelquintanilha.com" rel="follow"><strong>news website</strong></a>, I would want to get fresh content. Or maybe if I were following stock market prices, I would want real-time data. Social network feeds could also be a clear use case for dynamic, always-changing content. As you can see, the static approach was doomed.</p><p>With <em>dynamic </em>architecture, though, data is pulled routinely. That way, your newsfeed can be regularly updated without the need for <em>requesting </em>new information. Plus, if only <em>part </em>of the content changes, all you need to do is fetch that part, preventing you from having to download all the data again. It&#x2019;s a huge win.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/static-vs-dynamic-architecture--1-.png" class="kg-image" alt loading="lazy" width="1201" height="629" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/static-vs-dynamic-architecture--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/static-vs-dynamic-architecture--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/static-vs-dynamic-architecture--1-.png 1201w" sizes="(min-width: 720px) 720px"><figcaption>Static vs dynamic architecture</figcaption></figure><p>That model enabled the boom of <em>web applications</em>, given that web pages started to get more dynamic, more interactive, more powerful, and faster. Data is being constantly updated based on user actions, and because we are smart enough to pull only the freshest information, performance for complex applications has increased as well.</p><p>As good as it sounds, the dynamic model still has its flaws. First, because data is being constantly fetched, the application should be &#x201C;mounted&#x201D; on the fly, being loaded in chunks and either rendered asynchronously or after an unnecessarily long wait. Additionally, this wait is bad for SEO since the <em>web crawler </em>has to wait until the data is fetched and the page is mounted to be able to start properly indexing the application (and Google had limitations with that for years).</p><p>The static model overcomes these flaws. Because the content is already rendered and stored in the server, you download it only once (when you land on the page) and everything is ready to use. Crawlers are happy too &#x2014; they can start indexing your page right away, saving your <a href="https://developers.google.com/search/blog/2017/01/what-crawl-budget-means-for-googlebot?ref=rafaelquintanilha.com" rel="follow noopener"><strong>crawl budget</strong></a>. Faster loading times plus no waste of crawl budget equals a higher-ranked SEO page, which in turn means more organic users, less money spent on advertising, more revenue, and so on. In short: static sites are less flexible but more SEO-friendly. The big question then becomes: is it possible to make them more malleable and still retain the SEO benefits?</p><h2 id="enter-server-side-rendered-apps"><strong><strong><strong>Enter server-side rendered apps</strong></strong></strong></h2><p>Server-Side Rendering (SSR) applications are, as the name suggests, rendered on the server. How is that different from the traditional <em>static </em>model?</p><p>In SSR architecture, the application is regularly built during the build phase<em>. </em>In each build, the freshest data available is gathered, which means that every build has dynamic content. This solves the problem for applications that aren&#x2019;t time-sensitive. If your app can afford to update data, say, every 30 minutes, then an SSR approach might make sense for you. Every 30 minutes, you download the freshest data available, build (<em>render</em>) your page, and upload (<em>deploy</em>) the content to the server. Your users will then fetch the page as a static resource (like in the old days), and the content will be at most 30 minutes delayed.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/server-side-rendering--1-.png" class="kg-image" alt loading="lazy" width="1200" height="628" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/server-side-rendering--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/server-side-rendering--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/server-side-rendering--1-.png 1200w" sizes="(min-width: 720px) 720px"><figcaption>Server-Side Rendering</figcaption></figure><p>Or maybe you have a website with content that doesn&#x2019;t change very often, like a blog, but that you want to<em> </em>rebuild every time it changes (maybe a new edition is made or a new post is added.) In that scenario, you could set a <em>deploy hook </em>that would rebuild and deploy your application as needed.</p><p>Now, imagine this blog is really big. For example, it has thousands of entries. If you change page A, you really don&#x2019;t want to rebuild all the other entries. That can get really problematic at scale. In other words, the desired effect is to rebuild only the content that changed, nothing else. Now how are we able to do that?</p><h2 id="incremental-builds"><strong><strong><strong>Incremental builds</strong></strong></strong></h2><p>The answer to this question lies in <em>incremental builds. </em>As the name suggests, and our intuition indicates,<em> </em>incremental builds will build only what is necessary (i.e. what has been added or updated.) A <em>full build</em>, on the other hand, rebuilds the whole application at once, notwithstanding the number of pages and the time needed to accomplish this.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/standard-vs-incremental-build--1-.png" class="kg-image" alt loading="lazy" width="1201" height="629" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/standard-vs-incremental-build--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/standard-vs-incremental-build--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/standard-vs-incremental-build--1-.png 1201w" sizes="(min-width: 720px) 720px"><figcaption>Standard vs Incremental Builds</figcaption></figure><p>In the big blog example, it means that when page A is modified or added, the others won&#x2019;t be rebuilt. In terms of build time<em>, </em>this is a huge win&#x2014;the faster your website is rebuilt, the sooner your users will have access to fresh data.</p><p>The benefits are not limited to only blog posts but product catalogs, social network profiles, stock market indicators, and basically everything that is bound to be read from a CMS can potentially make the most of incremental builds. In general, if your app relies on data from another source&#x2014;for example, a CMS editor such as ButterCMS&#x2014;incremental builds are a really smart choice.</p><h3 id="when-not-to-use-incremental-builds"><strong><strong>When not to use Incremental Builds</strong></strong></h3><p>Sometimes it&apos;ll be in your best interest to<em> </em>do a full build. For example, if you add a new feature to your application that is visible throughout the app (say, a sidebar), you will want it to be present on every page.</p><p>Also, as mentioned before, if your application is sensitive to real-time data then an SSR approach (and, therefore, incremental builds) won&#x2019;t be adequate.</p><h2 id="gatsby%E2%80%99s-approach-to-incremental-builds"><strong><strong><strong>Gatsby&#x2019;s approach to incremental builds</strong></strong></strong></h2><p>When <a href="http://gatsbyjs.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby</strong></a> launched their <a href="https://www.gatsbyjs.com/products/cloud/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>cloud service</strong></a>, one of the main benefits was &#x2014; you guessed it &#x2014; incremental builds, a long-awaited feature of the community.</p><p>As expected, this approach became very popular&#x2014;to the point that since the launching of Gatsby v3 in March of 2021, <a href="https://www.gatsbyjs.com/blog/gatsby-v3/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>incremental builds became available to everyone</strong></a><em> by default. </em>Now, content creators who are integrating their CMS with Gatsby have this functionality right off the bat, allowing faster build times and better scalability.</p><p>Later, we will see how Gatsby&#x2019;s incremental builds work in practice.</p><h2 id="leveraging-incremental-builds-with-buttercms"><strong><strong><strong>Leveraging incremental builds with ButterCMS</strong></strong></strong></h2><p>I mentioned before that incremental builds are particularly interesting for content creators. It gets even better for users who use a <a href="https://buttercms.com/blog/what-is-headless-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>headless CMS</strong></a>.</p><p>A headless CMS is a data source that abstracts away the need to change <em>code </em>when all you want to change is <em>content</em>. Suppose you want to deploy a landing page for a brand-new product of yours. Well, you may be working closely with the marketing team, tweaking texts, adding images, changing colors, and so on in a never-ending search for perfection. Now, if you have a team of engineers, it&#x2019;s arguably not the best use of their time and expertise to tweak pixels on the screen.</p><p>A headless CMS is a solution for the aforementioned problem that delegates the creation of the landing page to a dedicated team and, later on, integrates the end result into your app.</p><p><a href="https://buttercms.com/?ref=rafaelquintanilha.com"><strong><strong><strong>ButterCMS</strong></strong></strong></a> is an excellent example of a headless CMS. Butter users can create and edit landing pages in addition to maintaining posts and other content while integrating it easily with several programming languages. One of the most popular is Gatsby, which has a <a href="https://www.gatsbyjs.com/docs/sourcing-from-buttercms/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>simple plugin</strong></a> to source data directly from ButterCMS in each build.</p><p>Now, if you have been following me since the beginning, you know what I&#x2019;m getting at: Gatsby enables incremental builds when content changes by default (since v3), and also integrates seamlessly with ButterCMS. ButterCMS, in turn, is a headless CMS that empowers content creators. Can we connect them all and testify to the miracle of <em>incremental builds with Gatsby and ButterCMS?</em> Heck, yeah.</p><p>In the next section, we will learn how to create a simple Gatsby website that sources data from ButterCMS. We will also deploy this application to <strong><a href="https://www.netlify.com/?ref=rafaelquintanilha.com" rel="follow noopener">Netlify</a></strong> to understand how incremental builds work in practice.</p><h2 id="tutorial-creating-a-simple-blog-using-buttercms-and-gatsby%E2%80%99s-incremental-builds"><strong><strong><strong>Tutorial: Creating a simple blog using ButterCMS and Gatsby&#x2019;s incremental builds</strong></strong></strong></h2><h3 id="before-you-begin"><strong><strong>Before you begin</strong></strong></h3><p>There are a couple of things you are going to need in order to follow through with this tutorial. One of them is a ButterCMS account. Go to <a href="https://buttercms.com/join?ref=rafaelquintanilha.com" rel="follow"><strong><strong><strong>https://buttercms.com/join</strong></strong></strong></a> and sign up, if you still haven&#x2019;t. Once you are logged in, click on your account and hit &#x201C;Settings.&#x201D; Select the &#x201C;API Keys&#x201D; tab and copy what is under &#x201C;Read API Token,&#x201D; which we will need to fetch information from Butter. Make sure to store it safely.</p><p>Next, make sure you have NodeJS installed. <a href="https://www.gatsbyjs.com/docs/tutorial/part-0/?ref=rafaelquintanilha.com#nodejs" rel="follow noopener"><strong>Gatsby&#x2019;s Docs have a section</strong></a> explaining how to do it for every OS. Also, it&#x2019;s a good idea to follow through with their tutorial if you are a complete newbie to Gatsby.</p><p>Finally, create an account on Netlify. We will host our application there (don&#x2019;t worry, it&#x2019;s free!) so we can see in practice how incremental builds work in a production environment. We&#x2019;ll get to that part later.</p><h3 id="what-were-building"><strong><strong>What we&apos;re building</strong></strong></h3><p>To showcase how incremental builds work, we are going to build an application that pulls posts from ButterCMS. We will render this content to our site and watch how builds react as content changes.</p><h3 id="step-1-creating-a-gatsby-app"><strong><strong>Step 1: Creating a Gatsby app</strong></strong></h3><p>The first thing to do is to create the Gatsby application. Follow their <strong><a href="https://www.gatsbyjs.com/docs/quick-start/?ref=rafaelquintanilha.com" rel="follow noopener">quick start</a></strong> to create an initial boilerplate. Don&#x2019;t worry about all the customizations; we are not going to need them now. After completing the quick start, make sure you can visit localhost:8000 and see your brand-new Gatsby app.</p><h3 id="step-2-sourcing-data-from-buttercms"><strong><strong>Step 2: Sourcing data from ButterCMS</strong></strong></h3><p>Our app is so far pretty simple. We are going to color it a bit by integrating data with ButterCMS. The first thing you want to do, if you haven&#x2019;t already, is to add some content in Butter!</p><p>In Butter&#x2019;s admin panel, click on &#x201C;Blog posts&#x201D; in the side menu and add a couple of entries. In the end, it should look something like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-buttercms-blog-posts--1-.png" class="kg-image" alt loading="lazy" width="1023" height="786" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/incremental-builds-buttercms-blog-posts--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/incremental-builds-buttercms-blog-posts--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-buttercms-blog-posts--1-.png 1023w" sizes="(min-width: 720px) 720px"><figcaption>ButterCMS admin panel</figcaption></figure><p>Now that we have actual content in our CMS, we are ready to <em>source it </em>in Gatsby. As mentioned before, Gatsby and Butter have a handy integration plugin called <em>gatsby-source-buttercms. </em>You can follow the <a href="https://www.gatsbyjs.com/docs/sourcing-from-buttercms/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>official docs from Gatsby</strong></a> for more context.</p><p>In your project&#x2019;s directory, add the plugin:</p><p><code>$ npm install gatsby-source-buttercms</code></p><p>Once the installation is done, open <em>gatsby-config.js </em>and add the following to the <em>plugins </em>array:</p><pre><code class="language-javascript">...
{
      resolve: `gatsby-source-buttercms`,
      options: {
        authToken: YOUR_TOKEN
      },
    },
}</code></pre><p>Replacing <em>YOUR_TOKEN </em>with the token you grabbed from Butter&#x2019;s panel before. If everything is correct, start the Gatsby server again and go to <a href="http://localhost:8000/___graphql?ref=rafaelquintanilha.com" rel="follow noopener"><strong>http://localhost:8000/___graphql</strong></a> where you should be able to see this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-local-host-1--1-.png" class="kg-image" alt loading="lazy" width="1111" height="559" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/incremental-builds-local-host-1--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/incremental-builds-local-host-1--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-local-host-1--1-.png 1111w" sizes="(min-width: 720px) 720px"><figcaption>GraphQL interface</figcaption></figure><p>Note how there are Butter <a href="https://www.gatsbyjs.com/docs/reference/graphql-data-layer/node-interface/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>nodes</strong></a> in the Explorer! You can easily test that the data is available by writing the following query to the interface:</p><pre><code class="language-javascript">query MyQuery {
  allButterPost {
    nodes {
      title
      author {
        first_name
        last_name
      }
    }
  }
}</code></pre><p>Now you should see the title of your posts and the author&#x2019;s name in the right-side panel. Nice job! Gatsby and ButterCMS are now hooked up!</p><h3 id="step-3-rendering-data-in-gatsby"><strong><strong>Step 3: Rendering data in Gatsby</strong></strong></h3><p>Now, our app is sourcing data from Butter, but we are still not seeing it. Thankfully, this is the easy part!</p><p>For our proof-of-concept, we are going to create three pages:</p><ol><li>A home page, which will have no information from Butter;</li><li>A blog index, which will render the title of all posts and link to them;</li><li>A post template, which will be used to dynamically render every post added in Butter.</li></ol><p>Our goal, when debugging incremental builds, will be to assert the following:</p><ul><li>A code change triggers a rebuild for all pages;</li><li>A content change triggers a rebuild only for the pages that contain that content (the blog index and the corresponding post):</li><li>As a corollary, if I change post A, then the home page and post B shouldn&#x2019;t be rebuilt.</li></ul><p>Create the blog index component:</p><pre><code class="language-javascript">import React from &quot;react&quot;;
import Layout from &quot;../components/layout&quot;;
import { useStaticQuery, graphql, Link } from &quot;gatsby&quot;;
import { content } from &quot;./blog.module.css&quot;;

const Blog = () =&gt; {
  const {
    allButterPost: { nodes: posts },
  } = useStaticQuery(graphql`
    query MyQuery {
      allButterPost {
        nodes {
          title
          slug
        }
      }
    }
  `);

  return (
    &lt;Layout&gt;
      &lt;div&gt;
        &lt;h1&gt;My Blog&lt;/h1&gt;
        &lt;ul className={content}&gt;
          {posts.map((post) =&gt; (
            &lt;li key={post.slug}&gt;
              &lt;Link to={`/blog/${post.slug}`}&gt;{post.title}&lt;/Link&gt;
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/Layout&gt;
  );
};

export default Blog;</code></pre><p>And the post template:</p><pre><code class="language-javascript">import React from &quot;react&quot;;
import { Link, graphql } from &quot;gatsby&quot;;
import Layout from &quot;./layout&quot;;
import { container, back, body } from &quot;./post.module.css&quot;;

const PostTemplate = ({ data }) =&gt; {
  return (
    &lt;Layout&gt;
      &lt;div className={container}&gt;
        &lt;Link className={back} to=&quot;/blog&quot;&gt;
          &#x21E6; Go back
        &lt;/Link&gt;
        &lt;h1&gt;{data.butterPost.title}&lt;/h1&gt;
        &lt;div
          className={body}
          dangerouslySetInnerHTML={{ __html: data.butterPost.body }}
        /&gt;
      &lt;/div&gt;
    &lt;/Layout&gt;
  );
};

export const query = graphql`
  query ($slug: String!) {
    butterPost(slug: { eq: $slug }) {
      title
      body
    }
  }
`;

export default PostTemplate;</code></pre><p>For the sake of simplicity, I&#x2019;m not going into Gatsby&#x2019;s details in this tutorial, but you have access to the full code at <a href="https://github.com/ButterCMS/gatsby-incremental-builds?ref=rafaelquintanilha.com" rel="follow noopener"><strong>https://github.com/ButterCMS/gatsby-incremental-builds</strong></a>. A live example can be found at <a href="https://incremental-builds.netlify.app/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>https://incremental-builds.netlify.app/</strong></a>.</p><p>If you follow through the repository (or clone it and switch the <em>authToken </em>with your own), you will see something like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-blog-page.gif" class="kg-image" alt loading="lazy" width="1033" height="803" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/incremental-builds-blog-page.gif 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/incremental-builds-blog-page.gif 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/incremental-builds-blog-page.gif 1033w" sizes="(min-width: 720px) 720px"><figcaption>Blog page</figcaption></figure><p>See how the content of the post you added in ButterCMS is correctly rendered in your app? Congratulations, you have successfully combined Butter and Gatsby!</p><h3 id="step-4-deploying-to-netlify"><strong><strong>Step 4: Deploying to Netlify</strong></strong></h3><p>Now that our app is complete, it&#x2019;s time to make it available to the world. <a href="https://app.netlify.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Log in to Netlify</strong></a> and click on &#x201C;New site from git.&#x201D;</p><p><em>Note: It&#x2019;s a good time to create a repository for your own app. I recommend </em><a href="https://github.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><em>GitHub</em></strong></a><em>. Follow the instructions on their website to store your code in the cloud and get Git benefits.</em></p><p><em>Warning: </em><strong><strong><em>do</em></strong></strong><em> </em><strong><strong><em>not </em></strong></strong><em>commit your ButterCMS token to any Git provider. When using Netlify, </em><a href="https://docs.netlify.com/configure-builds/environment-variables/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><em>Netlify environment variables</em></strong></a><em> are preferred instead.</em></p><p>When creating your new site, make sure to replace the <em>Build </em>command with:</p><p><code>gatsby build --verbose --log-pages</code></p><p>This will be necessary to gather more information about built pages. <a href="https://www.gatsbyjs.com/docs/debugging-incremental-builds/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby Docs</strong></a> have a dedicated page on how to debug incremental builds.</p><p>If all is good, you should be able to start a deploy for your app and see something like this in the logs:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/deploy-summary-1-1.png" class="kg-image" alt loading="lazy" width="340" height="321"><figcaption>Deploy summary</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/deploy-summary-2-1.png" class="kg-image" alt loading="lazy" width="453" height="216"><figcaption>Deploy logs</figcaption></figure><p>Note how Netlify discerns all pages and assets built during that phase. If you scroll down the logs, you will be able to see more detailed information on the number of pages updated and how long it took for Gatsby to build them.</p><h3 id="step-5-hooking-netlify-deploys-to-content-changes"><strong><strong>Step 5: Hooking Netlify deploys to content changes</strong></strong></h3><p>The penultimate step remaining in your build puzzle is to &#x201C;hook&#x201D; every change in Butter&#x2019;s content to a new deploy in Netlify. This way, every time a post is either published or updated in the Butter interface, we trigger a new build in Netlify. This build will generate new static assets (only if the content has changed) and then deploy them to the server. New visitors will be served with the updated content as soon as the deploy is complete.</p><p>In Netlify, go to &#x201C;Site settings&#x201D; and then &#x201C;Build &amp; deploy.&#x201D; Scroll down to &#x201C;Build hooks&#x201D; and click on &#x201C;Add build hook&#x201D;. Give it a descriptive name and, in the end, you should see something like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/netlify-build-hooks.png" class="kg-image" alt loading="lazy" width="922" height="327" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/netlify-build-hooks.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/netlify-build-hooks.png 922w" sizes="(min-width: 720px) 720px"><figcaption>Netlify Build hooks</figcaption></figure><p>Copy the URL (the &#x201C;hook&#x201D;) and head to Butter&#x2019;s panel. Go back to &#x201C;Settings&#x201D; again and, in the &#x201C;Webhooks&#x201D; tab, add the copied URL as the Target URL. Leave &#x201C;Header&#x201D; blank and select <em>post.published - blog post is published </em>in the Event field. Hit &#x201C;Save&#x201D; and we are done! Now, every time any post is published, a new build will be triggered.</p><p>In order to test that, go to your Blog posts and change something in one of the posts. Note that Netlify will automatically start a new build and that by the end of it only the affected pages (the post itself and the index with all posts) will be rebuilt!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/deploy-summary-after-change-1.png" class="kg-image" alt loading="lazy" width="372" height="221"><figcaption>Deploy summary after changes</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/deploy-summary-after-change-2.png" class="kg-image" alt loading="lazy" width="442" height="128"><figcaption>Deploy logs after changes</figcaption></figure><p>Note how this build was faster (10s now vs 15s before). Now, imagine the difference if you had hundreds or thousands of pages of static content!</p><p><em>Note: Due to cache reasons it might be that the incremental builds kick in only after you have rebuilt your site at least once.</em></p><p>As a final test, change something in your Gatsby code and push it to your Git provider. As expected, <em>all </em>pages will be rebuilt, as mentioned in <a href="https://www.gatsbyjs.com/docs/debugging-incremental-builds/?ref=rafaelquintanilha.com#expected-behaviors" rel="follow noopener"><strong>Gatsby&#x2019;s Docs as expected behavior</strong></a>. In short: incremental builds will be applied whenever <em>content </em>changes, but full builds are expected when your <em>code </em>changes.</p><h3 id="step-6-previewing-draft-content-before-publishing"><strong><strong>Step 6: Previewing draft content before publishing</strong></strong></h3><p>There is one last enhancement that can be done in order to streamline our process even more. In the previous step, we set up a webhook that rebuilds the website when a new post is <em>published </em>or <em>updated</em>. That&#x2019;s really great, but in a working environment, the experience would be subpar. Oftentimes, content creators will want to double-check and preview their work before publishing it to a production environment.</p><p>Luckily, there&#x2019;s a way to circumvent this limitation with ButterCMS! All we need to do is to set up a proper <em>staging </em>environment. I will walk you through how to do it in Netlify in a moment, but before that, create a <em>staging </em>branch in your repo:</p><p><code>$ git checkout -b staging</code></p><p>Now that you are in a different branch, the only code change needed is to tell <em>gatsby-source-buttercms</em> that you also want to source data in a <em>draft </em>state. Go to <em>gatsby-config.js </em>again and add the following line:</p><pre><code class="language-javascript">...
{
      resolve: `gatsby-source-buttercms`,
      options: {
        authToken: YOUR_TOKEN,
        preview: 1
      },
    },
}</code></pre><p>Surprisingly, that&#x2019;s all you need code-wise! As a side note, you could try to use environment variables to spawn multiple environments based on the same code.</p><p>Let us now set up the <em>staging </em>environment. Hop back to Netlify and create a new site. Again, we are taking the simpler step here. If you have a custom domain registered with Netlify, you can leverage <a href="https://docs.netlify.com/domains-https/custom-domains/multiple-domains/?ref=rafaelquintanilha.com#branch-subdomains" rel="follow noopener"><strong>branch subdomains</strong></a> instead of setting up a new site.</p><p>Repeat the procedure done in Step 4, only this time selecting <em>staging </em>as the &#x201C;Branch to deploy.&#x201D; Your configuration should look similar to this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/branch-to-deploy-configuration.png" class="kg-image" alt loading="lazy" width="725" height="880" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/branch-to-deploy-configuration.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/branch-to-deploy-configuration.png 725w" sizes="(min-width: 720px) 720px"><figcaption>Branch subdomains configuration</figcaption></figure><p>Proceed to deploy and don&#x2019;t forget to add your ButterCMS API key as an environment variable to the site recently created.</p><p>Next, repeat Step 5 and create a new webhook both in Netlify and ButterCMS. Make sure to add the URL generated by Netlify as the <em>Target URL</em> in Butter&#x2019;s Webhooks tab and, this time, select <em>post.draft - draft post is saved</em> in the Event field. Your Butter&#x2019;s webhooks should look like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/buttercms-webhooks.png" class="kg-image" alt loading="lazy" width="1345" height="543" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/buttercms-webhooks.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/buttercms-webhooks.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/buttercms-webhooks.png 1345w" sizes="(min-width: 720px) 720px"><figcaption>ButterCMS webhooks</figcaption></figure><p>As is, our app already has a working preview environment: every time a new draft post is <em>created</em> or <em>saved</em>, a webhook will be triggered to rebuild our <em>staging </em>site in Netlify. This way, content creators can iterate and observe how it looks on the real page before actually publishing to the production site.</p><p>The only caveat is that previewing happens <em>outside</em> Butter &#x2014; well, not anymore! The last step in this tutorial is to set up <em>Previews </em>in Butter&#x2019;s settings, which means that ButterCMS will become the one-stop shop for your content creators.</p><p>Click on the &#x201C;Previews&#x201D; tab and add the template URL to the <em>Blog Posts </em>field. In our case, it will look like: https://your-staging-site-url.netlify.app/blog/&lt;slug&gt;. The green part is what we defined in <em>gatsby-node.js</em>, only now using <em>&lt;slug&gt; </em>as the slug placeholder.</p><p>And that&#x2019;s it! All technical details are done. Try your setup by creating a new post, but instead of clicking on &#x201C;Publish,&#x201D; select &#x201C;Save draft.&#x201D; Check that only your staging site was rebuilt, while the production site remained unchanged. Compare how the blog index is different in the <a href="https://staging-incremental-builds.netlify.app/blog?ref=rafaelquintanilha.com" rel="follow noopener"><strong>staging</strong></a> and live <a href="https://incremental-builds.netlify.app/blog?ref=rafaelquintanilha.com" rel="follow noopener"><strong>production</strong></a> environments.</p><p>Note that you can keep editing your content in Butter and, whenever &#x201C;Save draft&#x201D; is clicked, a new rebuild will be triggered. Click on the &#x201C;Preview&#x201D; button while editing to see your changes right inside Butter&#x2019;s panel! Hopefully, once we are leveraging incremental builds, the rebuild will be really fast and the new content will be readily available.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/buttercms-preview-example--1-.png" class="kg-image" alt loading="lazy" width="1744" height="1250" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/buttercms-preview-example--1-.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/buttercms-preview-example--1-.png 1000w, https://www.rafaelquintanilha.com/content/images/size/w1600/2022/11/buttercms-preview-example--1-.png 1600w, https://www.rafaelquintanilha.com/content/images/2022/11/buttercms-preview-example--1-.png 1744w" sizes="(min-width: 720px) 720px"><figcaption>Previewing changes</figcaption></figure><h2 id="conclusion"><strong><strong><strong>Conclusion</strong></strong></strong></h2><p>Today, we learned the motivation behind incremental builds and the problems they are trying to solve. We gathered all information in a tutorial hooking up ButterCMS and Gatsby, which has incremental builds enabled for free by default since v3.</p><p>Incremental builds are and will no doubt continue to be beneficial for content creators, especially the ones leveraging a Gatsby-compatible <a href="https://buttercms.com/blog/what-is-headless-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>headless CMS</strong></a> such as ButterCMS. By significantly decreasing build times, your website will be able to scale properly as new content is added for the enjoyment of your audience.</p>]]></content:encoded></item><item><title><![CDATA[How to Rebuild Static Sites at Fixed Intervals with Netlify and GitHub Actions]]></title><description><![CDATA[Learn how to schedule redeployments at regular intervals by building a simple application that fetches stock market data.]]></description><link>https://www.rafaelquintanilha.com/how-to-rebuild-static-sites-at-fixed-intervals-with-netlify-and-github-actions/</link><guid isPermaLink="false">6383a8f614168e003dd8f6e6</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[Netlify]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Tue, 15 Jun 2021 18:23:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/illustration-edit-cron-jobs.jpg" class="kg-image" alt loading="lazy" width="600" height="600" srcset="https://www.rafaelquintanilha.com/content/images/2022/11/illustration-edit-cron-jobs.jpg 600w"><figcaption>Setting up cron jobs with GitHub Actions and Netlify</figcaption></figure><p>Back in the old days, websites were all static. That meant that all content rendered on the page was fetched previously from the server and no change would take place until the files were updated. Time has passed and the need for <em>dynamic </em>data has increased &#x2014; now users are demanding faster, timelier updates and the traditional model has become outdated.</p><p>Technologies like React, which can be used with our <a href="https://buttercms.com/react-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>React CMS</strong></a>, popularized the concept of client-side apps, where the browser would download the JavaScript from the server and render the whole app from there. If further data was needed, the application would issue as many HTTP requests as needed in order to get recent, up-to-date information.</p><p>The idea was great and people quickly adopted it. However, this approach had some shortcomings: because the application had to be constructed from scratch <em>after </em>the JavaScript was downloaded <em>and</em> parsed, larger apps could face performance issues. Moreover, SEO was a problem since web crawlers had less time to get available content to index your web page (only after <a href="https://searchengineland.com/tested-googlebot-crawls-javascript-heres-learned-220157?ref=rafaelquintanilha.com" rel="follow noopener"><strong>they got smart enough to crawl JavaScript</strong></a>).</p><p>In order to address these issues and retain the good from the dynamic approach, the concept of <em>server-side rendered </em>applications was introduced. Now, the app is rendered on the server during a phase called <em>build time</em>, which yields a bunch of static files to be served very much like the old days. During build time, data can be sourced from different places (e.g. a database, an external API, etc), which enables the static file to actually have dynamic information.</p><p>Now, considering that all data is fetched during build time, the app is as up-to-date as the last build. This means that if you don&#x2019;t routinely <em>rebuild </em>it, your app won&#x2019;t differ very much from the traditional model.</p><p>The goal of this article is to explain how you can easily set up and edit cron jobs to schedule a build for your static website at regular intervals, so you can use the latest cutting-edge tools for web development and still retain the ability to create SEO-friendly applications.</p><h2 id="what-is-a-cron-job"><strong>What is a cron job?</strong></h2><p>A <em>cron job </em>is simply a task scheduled to be executed at defined intervals. You can instruct a computer program to perform a routine at those intervals using a <em>crontab</em>.</p><p>Crontabs follow a specific structure that can be quickly learned. Fortunately, there are applications such as <a href="https://crontab.guru/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>crontab guru</strong></a> that help you to edit cron jobs very easily. Diving into the specifics of crontabs is out of the scope of this article, but as a quick example, the following is the cron structure necessary to run a task at 8 pm every weekday:</p><!--kg-card-begin: html--><pre>
0  20  *  *  1-5
</pre><!--kg-card-end: html--><p>The first position (0) is the <em>minute </em>that the task must be executed. The next one (20), is the hour. Combining both, we are instructing the computer to execute the task at minute 0 of the 20th hour (8 pm).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/edit-cron-jobs.png" class="kg-image" alt loading="lazy" width="600" height="600" srcset="https://www.rafaelquintanilha.com/content/images/2022/11/edit-cron-jobs.png 600w"><figcaption>Editing cron jobs illustration</figcaption></figure><p>The third position states the <em>day of the month, </em>while the fourth position is about the <em>month </em>itself. An asterisk means that <em>any </em>value is fine for both entries. Finally, the last value is the day of the week, where we are instructing the computer to only execute on days 1 to 5 (starting from 0, which is Sunday). Therefore, only days from Monday to Friday are included. We can view a nice, human-readable description of cron <a href="https://crontab.guru/?ref=rafaelquintanilha.com#0_18_*_*_1-5" rel="follow noopener"><strong>here</strong></a>.</p><h2 id="netlify-build"><strong>Netlify Build</strong></h2><p>Earlier we learned that <em>server-side rendered </em>applications render static files during their <em>build</em>. In a production environment, it is important that you are able to automatically <em>trigger </em>a build so you can set up a workflow for the deployment of your website.</p><p>One of the many tools available nowadays is <a href="https://www.netlify.com/products/build/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Netlify Build</strong></a>. Netlify Build is a modern way to go from code to deployment without too much of a hassle. As the name suggests, it takes care of building your website and deploying the output to the internet. There are several articles explaining how to use Netlify and its benefits (including <a href="https://buttercms.com/blog/what-is-serverless-and-how-to-use-it-in-practice/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>What is Serverless and How to Use It in Practice</strong></a>) but if you haven&#x2019;t used it yet, don&#x2019;t worry &#x2014; we are going to see how it works step by step.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/website-build.png" class="kg-image" alt loading="lazy" width="600" height="600" srcset="https://www.rafaelquintanilha.com/content/images/2022/11/website-build.png 600w"><figcaption>Netlify and GitHub communicating</figcaption></figure><h3 id="build-hooks">Build hooks</h3><p>Considering that Netlify allows you to trigger builds, a natural question is how can you programmatically instruct Netlify that a build is due.</p><p>Fortunately, Netlify provides what are called <a href="https://docs.netlify.com/configure-builds/build-hooks/?ref=rafaelquintanilha.com" rel="follow noopener"><strong><em>build hooks</em></strong></a>. In their own words, <em>build hooks are URLs you can use to trigger new builds and deploys</em>. It means that every time you make a POST request to the provided URL, you are able to trigger a build.</p><p>We are getting closer to our goal: we know already that we can rebuild and deploy static websites using Netlify and that there is a unique URL that can be used to trigger a build programmatically. If we find a way to make POST requests at regular intervals, then we will be able to schedule builds for our static website.</p><h2 id="github-actions"><strong>GitHub Actions</strong></h2><p>The answer to this problem lies in a feature called <a href="https://github.com/features/actions?ref=rafaelquintanilha.com" rel="follow noopener"><strong>GitHub Actions</strong></a>. Actions are a very powerful service offered by GitHub that can leverage your application&#x2019;s CI/CD (continuous integration and deployment) workflow. We are not getting into details of all the advantages that Actions can provide to you, but I suggest reading <a href="https://docs.github.com/en/actions?ref=rafaelquintanilha.com" rel="follow noopener"><strong>their docs</strong></a> in order to get a broader understanding of it.</p><p>For today, what is important is that GitHub Actions allow us to issue a cURL request at regular intervals. This fills the last piece of our puzzle. Here&#x2019;s how our workflow looks:</p><ol><li>Host server-side rendered application on Netlify and generate unique build hook URL;</li><li>Set up a GitHub action to make a POST request to that URL at regular intervals;</li><li>Enjoy a fast, SEO-friendly application using cutting-edge technologies with data updated as scheduled.</li></ol><p>We are going to fit all the pieces together in a practical project, but before we get into it, let us discuss the implications and shortcomings of such an approach.</p><h2 id="limitations-of-scheduled-cron-jobs"><strong>Limitations of scheduled cron jobs</strong></h2><p>All looks very well but as with everything in life, there are some constraints.</p><p>Most importantly, even if we schedule builds at reduced intervals, our data will never be <em>real-time.</em> As always, it is part of the engineering job to decide the best tool for the task at hand, and if your application is very sensitive to real-time information, going server-side rendered might not be the best choice for you.</p><p>Moreover, if you significantly reduce the interval, you will perform more builds, which means that you are going to spend more <em>build minutes</em>. Many build tools charge by the minute, and even though most services will provide you a free tier, triggering too many builds can stack up minutes quickly and cost you a lot of money.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/performance-issues.png" class="kg-image" alt loading="lazy" width="600" height="600" srcset="https://www.rafaelquintanilha.com/content/images/2022/11/performance-issues.png 600w"><figcaption>Waiting for your code to execute</figcaption></figure><p>Also note that if your build is heavy, meaning that it fetches too much information or builds too many pages, every build will also take more time to complete. This will directly impact costs.</p><p>That said, setting up cron jobs to trigger static builds is a fairly elegant solution if your application can afford small delays (like updating once a day or every X hours). Remember that the ultimate goals for a static website are to be <em>fast </em>and <em>SEO-friendly</em>, and if you have dynamic, real-time pages, such as a social network feed, you probably won&#x2019;t want it to be statically rendered anyway.</p><p>Enough talk. Let&apos;s learn how to implement all the concepts explained so far in a practical project.</p><h2 id="how-to-schedule-and-edit-cron-jobs"><strong>How to schedule and edit cron jobs</strong></h2><p>To illustrate the process, we will create a basic static stock price website. Our project will be very simple: we are going to build an application where users will be able to check how much the stock prices of FAANG companies have changed since the last trading day.</p><p>The application will be statically generated using <a href="https://www.gatsbyjs.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>GatsbyJS</strong></a> and will fetch data from <a href="https://finance.yahoo.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Yahoo Finance&#x2019;s API</strong></a>. On top of that, we will set up a GitHub Action to trigger a build every workday at the end of the regular trading session (4 pm ET or 8 pm UTC). You can check the source code at any point on the <a href="https://github.com/rafaelquintanilha/faang-variation?ref=rafaelquintanilha.com" rel="follow noopener"><strong>GitHub repo</strong></a>. The final version will look like <a href="http://faangvariation.netlify.app/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>this</strong></a>.</p><h3 id="step-1-cloning-the-gatsby-repository">Step 1: Cloning the Gatsby repository</h3><p>In order to start with Gatsby, make sure you have <a href="https://www.gatsbyjs.com/docs/quick-start/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby&#x2019;s CLI installed on your machine</strong></a>. Once you have it, run the following commands in your terminal to create a new project and start the default application:</p><pre><code class="language-shell">$ gatsby new faang-variation
$ cd faang-variation
$ gatsby develop</code></pre><p>Go to <a href="http://localhost:8000/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>http://localhost:8000/</strong></a> and check that the app is up and running.</p><h3 id="step-2-fetching-data-from-the-api">Step 2: Fetching data from the API</h3><p>A server-side rendered application will typically fetch information from multiple sources. Today, we are going to use Yahoo Finance&#x2019;s API to achieve our goal. The <a href="https://www.npmjs.com/package/yahoo-finance?ref=rafaelquintanilha.com" rel="follow noopener"><strong>yahoo-finance</strong></a> module is all we need:</p><pre><code class="language-shell">$ yarn add yahoo-finance</code></pre><p>With the module installed, it&#x2019;s time to edit <em>gatsby-node.js</em>. <a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby Node API</strong></a> is an interface provided by Gatsby that allows us to dynamically generate static pages, which is precisely what we need.</p><p>Add the following to your <a href="https://github.com/rafaelquintanilha/faang-variation/blob/master/gatsby-node.js?ref=rafaelquintanilha.com" rel="follow noopener"><strong>gatsby-node.js</strong></a>:</p><pre><code class="language-javascript">const yf = require(&quot;yahoo-finance&quot;)
const path = require(`path`)

exports.createPages = async ({ actions: { createPage } }) =&gt; {
 const homePageTemplate = path.resolve(`src/components/Home.js`)

 const symbols = [&quot;FB&quot;, &quot;AMZN&quot;, &quot;AAPL&quot;, &quot;NFLX&quot;, &quot;GOOG&quot;]
 const prices = await yf.quote({
   symbols,
   modules: [&quot;price&quot;],
 })

 const buildTime = new Date()

 createPage({
   path: `/`,
   component: homePageTemplate,
   context: {
     prices,
     buildTime,
   },
 })
}</code></pre><p>The code should be very straightforward: we are quoting prices for our desired stocks and recording the build time. Next, we use the <a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/?ref=rafaelquintanilha.com#createPages" rel="follow noopener"><strong>createPage function</strong></a> to generate our home page using the Home component at <a href="https://github.com/rafaelquintanilha/faang-variation/blob/master/src/components/Home.js?ref=rafaelquintanilha.com" rel="follow noopener"><strong><em>src/components/Home.js</em></strong></a><em> </em>as a template.</p><h3 id="step-3-create-the-home-component">Step 3: Create the Home component</h3><p>Now that we already have the stock information available at build time in Gatsby, the final piece of the app is to actually create the Home component, which we will use to render the content based on data.</p><p>Go ahead and delete the <em>pages </em>folder, which has a static <em>index.js</em> file that we won&#x2019;t be using. Then, create <em>Home.js </em>in <em>src/components </em>and add the following:</p><pre><code class="language-javascript">import React from &quot;react&quot;

const Home = ({ pageContext: { prices, buildTime } }) =&gt; {
  return (
    /* Code here */
  )
}

export default Home</code></pre><p>The actual UI is not relevant. What really matters is that you can access the prices and buildTime variables generated in the previous step, using the pageContext prop of the component.</p><p>If you copy the code from GitHub and start the server again, you should be able to see our simple app up and running!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--25-.png" class="kg-image" alt loading="lazy" width="611" height="379" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/image--25-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/image--25-.png 611w"><figcaption>FAANG Stock Price Variation Website</figcaption></figure><h3 id="step-4-deploy-to-netlify">Step 4: Deploy to Netlify</h3><p>For this step, I am assuming you have your code hosted on a GitHub repository. Our app is ready, so it&#x2019;s time to make it available to the world.</p><p>Make sure you have already signed up to Netlify. After this is done, go to <a href="https://app.netlify.com/start?ref=rafaelquintanilha.com" rel="follow noopener"><strong>https://app.netlify.com/start</strong></a> in order to connect your GitHub repository.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--26-.png" class="kg-image" alt loading="lazy" width="615" height="470" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/image--26-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/image--26-.png 615w"><figcaption>Create a new site in Netlify</figcaption></figure><p>Click on &#x201C;GitHub&#x201D; and authorize the integration. Next, select your repo and proceed to deploy:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--27-.png" class="kg-image" alt loading="lazy" width="569" height="473"><figcaption>Configure site settings</figcaption></figure><p>It&#x2019;s that simple. In a few minutes, your website will be available. Change the domain name if you want and it&#x2019;s done! The live result <a href="https://faangvariation.netlify.app/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>can be seen here</strong></a>.</p><h3 id="step-5-add-build-hook">Step 5: Add build hook</h3><p>The ultimate goal of today&#x2019;s article is to set up a cron job that will trigger a build every weekday at 8 pm UTC. As discussed before, first we need to get a unique URL to which we will issue a POST request.</p><p>Go to Netlify &gt; Site settings, then select &#x201C;Build &amp; deploy&#x201D; and scroll to &#x201C;Build hooks.&#x201D; Click to add a new hook and fill it up with some descriptive information:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--28-.png" class="kg-image" alt loading="lazy" width="594" height="379"><figcaption>Add Build hooks</figcaption></figure><p>After you save it, a unique URL will be available to you.</p><h3 id="step-6-schedule-curl-requests-with-github-actions">Step 6: Schedule cURL requests with GitHub Actions</h3><p>Finally, we are ready to integrate with GitHub Actions in order to schedule the builds. But before we jump into that, let&#x2019;s make sure the build hook is working.</p><p>Open your terminal and run the following command, replacing BUILD_HOOK_URL with the URL you generated before.</p><pre><code class="language-shell">$ curl -X POST -d {} BUILD_HOOK_URL</code></pre><p>Go back to <em>Site overview</em> in Netlify and make sure you see something like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--29-.png" class="kg-image" alt loading="lazy" width="577" height="227"><figcaption>Deploys in Netlify</figcaption></figure><p>The hook is working! Now go to your GitHub repository, click on &#x201C;Actions&#x201D; and then on &#x201C;set up a workflow yourself&#x201D;.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/image--30-.png" class="kg-image" alt loading="lazy" width="618" height="438" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/image--30-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/image--30-.png 618w"><figcaption>Configuring GitHub Actions</figcaption></figure><p>Finally, get rid of everything on the left side editor and add the following (again, replace BUILD_HOOK_URL with your own):</p><pre><code class="language-yaml">name: Trigger Netlify Build
on:
  schedule:
    # &#x201C;At 20:00 on every day-of-week from Monday through Friday.&#x201D;
    # https://crontab.guru/#0_20_*_*_1-5
    - cron: &apos;0 20 * * 1-5&apos;
jobs:
  build:
    name: Build Hook
    runs-on: ubuntu-latest
    steps:
      - name: Curl request
        run: curl -X POST -d {} BUILD_HOOK_URL</code></pre><p>Commit your changes and that&#x2019;s it! You have now learned how to edit cron jobs in order to schedule builds for your static application.</p><h2 id="final-thoughts"><strong>Final thoughts</strong></h2><p>Static sites are very fast and <a href="https://buttercms.com/kb/seo-optimization?ref=rafaelquintanilha.com" rel="follow"><strong>great for SEO</strong></a>, which makes them very appealing when designing your application. However, those benefits come with drawbacks, especially if you want data to be regularly updated.</p><p>Scheduling cron jobs is a viable solution assuming that you can afford some delay when triggering your rebuilds. Note that the smaller the delay, the more builds will run, and the more expensive it will be for you to adopt this strategy (however, most services will provide you some kind of free tier if you want to test it out).</p><p>This approach is very useful if you use a <a href="https://buttercms.com/blog/what-is-headless-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>headless CMS</strong></a> such as ButterCMS with a javascript framework like React. Consider this strategy to regularly update the content on your page!</p>]]></content:encoded></item><item><title><![CDATA[React SEO: How to Build Search-Friendly Pages in React]]></title><description><![CDATA[How to boost your React app SEO ranking with many practical tips.]]></description><link>https://www.rafaelquintanilha.com/react-seo-how-to-build-search-friendly-pages-in-react/</link><guid isPermaLink="false">6383abfb14168e003dd8f748</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[SEO]]></category><category><![CDATA[Best Practices]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Thu, 21 Jan 2021 18:27:00 GMT</pubDate><content:encoded><![CDATA[<p>Digital advertising is a multi-billionaire industry that has been rising sharply. In fact, the money spent worldwide on it has <a href="https://www.statista.com/statistics/237974/online-advertising-spending-worldwide/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>nearly doubled</strong></a> since 2016. The motive for this is clear: companies want to be seen on the Internet.</p><p>On the one hand, you can pay a large number of dollars to have your ad featured; on the other hand, you can be seen for free. That&#x2019;s due to SEO, or Search Engine Optimization. Attracting organic traffic to your website is one of the most profitable actions a business can take, and this is by no means a trivial thing to achieve.</p><p>In this article, I&#x2019;ll guide you on how to build SEO-friendly pages using React, the most popular framework for building modern websites. I&apos;ll also show you how these methods can be applied to dynamic content with the help of a <a href="https://buttercms.com/react-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>good React CMS</strong></a>.</p><h2 id="the-importance-of-seo"><strong>The Importance of SEO</strong></h2><p>Google owns 92% of the search engine market share worldwide and this number has been fairly <a href="https://gs.statcounter.com/search-engine-market-share?ref=rafaelquintanilha.com#yearly-2009-2020" rel="follow noopener"><strong>steady since 2009</strong></a>. It makes sense, then, to target Google and what it considers good practice when developing your SEO strategy.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/react-seo-search-engine-market-share.png" class="kg-image" alt loading="lazy" width="1200" height="628" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/react-seo-search-engine-market-share.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/react-seo-search-engine-market-share.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/react-seo-search-engine-market-share.png 1200w" sizes="(min-width: 720px) 720px"><figcaption>Search Engine Market Share (2020)</figcaption></figure><p>The core concept is that the higher your website ranks on the Search Results Page (SERP), the higher the likelihood that users will click on it. While this is fairly intuitive, what might surprise you is how large the gap is in click-through rates (CTR) in the first positions &#x2014; <strong><a href="https://www.smartinsights.com/search-engine-optimisation-seo/seo-analytics/comparison-of-google-clickthrough-rates-by-position/?ref=rafaelquintanilha.com" rel="follow noopener">recent studies</a></strong> have found that the combined click-through rates for positions 1 and 2 on a SERP are approximately double the combined click-through rates for positions 3 and 4! In other words, your effectiveness in being seen is exponentially affected by how well you fare on the results page.</p><h2 id="how-google-ranks-your-website"><strong>How Google Ranks Your Website</strong></h2><p>Before we learn how to enhance React SEO, we must understand how the process works. Simply put, Google uses a bot called Googlebot (how creative!) to crawl your application. This robot is called a <em>web crawler</em>.</p><p>The crawler will load your application, analyze it, and rank it by a set number of criteria. While exactly how each criterion is evaluated is unknown, one should target as many features as possible. An application optimized for SEO will enforce some rules to increase the likelihood of being highly ranked.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/react-seo-meta-tags.png" class="kg-image" alt loading="lazy" width="1146" height="584" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/react-seo-meta-tags.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/react-seo-meta-tags.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/react-seo-meta-tags.png 1146w" sizes="(min-width: 720px) 720px"><figcaption>Meta tags</figcaption></figure><h3 id="crawling-budget">Crawling Budget</h3><p>We live in an era of limited resources, and this will always be true. The same concept applies to search engines and their crawlers &#x2014; they need to spend their time wisely. The result of this policy is what is called a <em>crawling budget</em>, or how much time a crawler will spend analyzing your website. As you might guess, how efficiently Google will parse your application is severely impacted by your app speed. Any effort to improve load time is welcome, which can become a problem for React apps.</p><h3 id="accessible-urls">Accessible URLs</h3><p>It is imperative for React SEO to have an SEO-friendly URL. In Google&#x2019;s words: <em>&#x201C;URLs with words that are relevant to your site&apos;s content and structure are friendlier for visitors navigating your site.&#x201D;</em> The full set of <strong><a href="https://developers.google.com/search/docs/beginner/seo-starter-guide?hl=en&amp;visit_id=637438582413772187-2328543862&amp;rd=1&amp;ref=rafaelquintanilha.com#best-practices_6" rel="follow noopener">best practices can be seen here</a></strong>. This factor turns out to be one of the major problems with Single Page Applications (SPA), such as regular React applications. Once SPAs are evaluated on the client side, the whole application can live within a single URL.</p><p>Several other factors affect React SEO. However, the above are the most flagrant shortcomings of a React application and will be the object of discussion for the next sections.</p><h2 id="react-seo-the-problem-with-react-applications"><strong>React SEO: The Problem with React Applications</strong></h2><p>So far we have learned that search engines use robots called crawlers to parse your website and rank them accordingly in their SERP. Unfortunately, several of the aspects that are valuable to search engines are not found in standard React applications. We will now analyze what exactly React&#x2019;s limitations are and, later on, learn how we can overcome them.</p><h3 id="static-vs-dynamic-sites">Static vs Dynamic Sites</h3><p>Back in the day, all web pages were called <em>static. </em>The process is as follows: the user makes a request to a server for a given URL. The server then returns a set of HTML, JavaScript, and CSS files that are served on-demand and rendered on the user&#x2019;s browser.</p><p>This old-fashioned process is ideal for robots &#x2014; they have all assets for that web page when they access it. However, things changed and web applications became more complex. The content is many times <em>dynamic</em>, meaning that it changes constantly. Think about your Twitter feed: all content is in constant motion, even though the URL remains the same.</p><p>Dynamic content is a problem for crawlers once the data might not be available during their crawling time (remember the crawling budget?). Also, it is loaded via JavaScript, meaning the browser needs to <em>render </em>and <em>parse </em>the code before anyone can see anything. This substantially increases the time a crawler needs to parse the content, hence affecting your SEO.</p><h3 id="how-spas-work">How SPAs Work</h3><p>As mentioned before, React is a Single Page Application. This means that your whole app lives on a single page, even though you can simulate different routes and pages.</p><p>While SPAs are very convenient for dynamic applications, they lack good SEO support. For starters, if all you have is a single page, your meta tags will hardly describe accurately each part of your application. Moreover, you won&#x2019;t be able to generate unique URLs out-of-the-box, resorting to a <em>client-side routing </em>library like <strong><a href="https://reactrouter.com/?ref=rafaelquintanilha.com" rel="follow noopener">react-router</a></strong>.</p><p>And finally, an SPA is a single webpage where JavaScript is responsible for updating the content on the screen. That usually means that the JavaScript code is bulky, which leads to a higher parse time by the browser. Ultimately, your application will load slower (due to the time needed to download + parse a larger JavaScript file) and your crawling budget will run out quickly.</p><p>It all looks like React applications are doomed to rot on the dark corners of the SERP, but it doesn&#x2019;t need to be that way. Next, we will learn how to overcome the aforementioned issues.</p><h2 id="server-side-rendering"><strong>Server-Side Rendering</strong></h2><p>Server-side rendering (SSR), also known as <em>isomorphic applications</em>, is a clever solution to the SPAs shortcomings.</p><p>In order to avoid the single page with bulky JavaScript, the React community evolved to a model where the application is rendered on the server during <em>build time</em>. That means that instead of sending a large JavaScript file to the client and letting it figure out what to render, a compiler will analyze the code on the server and generate multiple pages. These pages will then be served on their specific routes, in the good ol&#x2019; static website model.</p><p>The advantage of such a model is that you can keep working with a cutting-edge library such as React and still retain the biggest advantage of static websites &#x2014; blazing-fast load times!</p><p>However, it is a product decision to understand if SSR is ideal for your project. As a rule of thumb, if your application has content that changes <em>too </em>often, client-side applications should be the best option. Now, if your content is mostly static, and you have many web pages that would benefit from being found on a search engine (such as a product landing page or a blog post), SSR is the way to go.</p><h2 id="implementing-an-ssr-application-in-react"><strong>Implementing an SSR Application in React</strong></h2><p>The most famous frameworks for developing SSR applications are <a href="http://gatsbyjs.com/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Gatsby</strong></a> and <a href="https://nextjs.org/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Next.js</strong></a>. Although there are differences between them, their main goal is similar: to allow next-generation web applications to remain blazing-fast.</p><p>It is beyond the scope of this article to compare both technologies, but I will use Gatsby as an example of how the framework addresses the React SEO dilemma.</p><h3 id="react-helmet">React-helmet</h3><p><a href="https://github.com/nfl/react-helmet?ref=rafaelquintanilha.com" rel="follow noopener"><strong>React-helmet</strong></a> is the industry standard for meta tags optimization. It allows every page to have its own custom meta tags, what we have seen is a major victory for React SEO. The library also allows for the addition of <a href="https://ogp.me/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>Open Graph</strong></a>, which directly impacts the shareability of your content on potentially highly viral spaces such as social networks.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/react-helmet-react-seo-plugin.png" class="kg-image" alt loading="lazy" width="906" height="309" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/react-helmet-react-seo-plugin.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/react-helmet-react-seo-plugin.png 906w" sizes="(min-width: 720px) 720px"><figcaption>React Helmet SEO plugin</figcaption></figure><p>Fortunately, Gatsby provides a wide set of plugins that can be used to simplify your life as a developer. The <a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-react-helmet/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>gatsby-plugin-react-helmet</strong></a> repository is one of the most used and widely maintained plugins in the ecosystem.</p><p>If you haven&#x2019;t tried it already, <a href="https://www.gatsbyjs.com/tutorial/seo-and-social-sharing-cards-tutorial/?ref=rafaelquintanilha.com#reach-skip-nav" rel="follow noopener"><strong>this comprehensive tutorial</strong></a> will help you get up on your feet with Gatsby and react-helmet.</p><h3 id="gatsby-image">Gatsby-image</h3><p>We have repeatedly insisted on how harmful to your React SEO score large JavaScript files are. However, I have never found a potential performance threat as strong as images.</p><p>Developers often optimize too much of what is in their control &#x2014; dependencies, code splitting, etc. But many overlook that a large image loaded on your website can severely impact its performance. While code is under control, static assets are often not. They are provided by content creators, marketers, authors, and others. Therefore, we need a plan to mitigate the potential impacts.</p><p>My favorite solution for this problem is <a href="https://www.gatsbyjs.com/plugins/gatsby-image/?ref=rafaelquintanilha.com" rel="follow noopener"><strong>gatsby-image</strong></a>, another plugin meant to save your life. Gatsby-image takes care of, among several other things, optimizing your images and serving them in the most efficient and responsive format. It enhances the look and feel of your app, not to mention the performance and ultimate SEO gain.</p><h3 id="other-plugins">Other Plugins</h3><p>Gatsby has a <a href="https://www.gatsbyjs.com/plugins?ref=rafaelquintanilha.com" rel="follow noopener"><strong>vast library of plugins</strong></a>. Many of them are zero-config, meaning that you gain React SEO without much more effort than an <em>npm install</em>. As an example, <a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-sitemap?ref=rafaelquintanilha.com" rel="follow noopener"><strong>gatsby-plugin-sitemap</strong></a> will generate sitemaps for your web page, helping bots to crawl your content in the right way.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-plugin-library.png" class="kg-image" alt loading="lazy" width="1228" height="767" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/gatsby-plugin-library.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/gatsby-plugin-library.png 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-plugin-library.png 1228w" sizes="(min-width: 720px) 720px"><figcaption>Gatsby Plugin Library</figcaption></figure><h3 id="route-based-code-splitting">Route-based Code Splitting</h3><p>Another great feature of Gatsby is the ability to serve static pages in their own URL (thus addressing the <em>Accessible URLs </em>point<em>)</em> and be wise about what should be included in that particular page.</p><p>Remember how SPAs are penalized by having large chunks of JavaScript being loaded at all times? With route-based code splitting, the only JavaScript code sent from the server to the client will be necessary to render whatever is on that particular page. <a href="https://www.gatsbyjs.com/blog/2019-04-02-behind-the-scenes-what-makes-gatsby-great/?ref=rafaelquintanilha.com#route-based-code-splitting" rel="follow noopener"><strong>The following article describes in detail</strong></a> how it works.</p><h3 id="do-i-need-a-static-site-generator">Do I Need a Static Site Generator?</h3><p>By all means, every advantage listed in the previous topics can be achieved with vanilla JavaScript and other tools. However, <strong><a href="https://buttercms.com/blog/6-of-the-best-static-site-generators-in-2020/?ref=rafaelquintanilha.com" rel="follow">SSGs like Gatsby and Next.js</a></strong> will abstract the hassle from you to the point that the standard Gatsby application is born with a 100 SEO score on <strong><a href="https://developers.google.com/web/tools/lighthouse?ref=rafaelquintanilha.com" rel="follow noopener">Lighthouse</a></strong>, Google&#x2019;s performance analyzer.</p><p>More than recommending framework A or B, the goal of this post is to outline the importance of SEO, the shortcomings of barebone React applications, and which tools can be used to overcome them. Don&#x2019;t feel pressured to switch and adopt a new technology tomorrow &#x2014; but be aware that different businesses have different needs and it is your job to find the right tool.</p><h2 id="static-sites-can-be-dynamic"><strong>Static Sites Can Be Dynamic</strong></h2><p>The last point worth mentioning is that, in fact, static sites can have dynamic content. Yes, I know I said before that they are two different kinds of applications, but bear with me for a moment.</p><p>If you opt for a Server Side Rendering strategy, your deployment process will include a <em>building time</em>. During this period, the framework will fetch the most up-to-date data available and construct the static page. That means that the <em>source </em>of data can constantly be changing!</p><p>This ends up being one of the main advantages of such a process, given that it allows the leverage of a <a href="https://buttercms.com/blog/what-is-headless-cms/?ref=rafaelquintanilha.com" rel="follow"><strong><em>headless CMS</em></strong></a> such as ButterCMS. Using this strategy, you can have your Gatsby application connected to ButterCMS and fetch all content from an external admin panel. The main advantage is the possibility to offload the need to constantly edit static content onto professionals better suited for such actions, like marketers and copywriters.</p><p>Every time a change is made to static content, or in defined intervals, a new build will be triggered, and once it is finished your content will be updated. The process is highly SEO-friendly and, when properly designed, will allow content creators to choose the best features for the web crawler carefully.</p><p>ButterCMS is a leading <a href="https://buttercms.com/gatsbyjs-cms/?ref=rafaelquintanilha.com" rel="follow"><strong>Gatsby CMS</strong></a>, and you can set up the integration with your Gatsby application in minutes!</p>]]></content:encoded></item><item><title><![CDATA[Converting Jupyter Notebooks Into Blog Posts with Gatsby]]></title><description><![CDATA[Learn how to bring your Data Science projects to life in easy steps.]]></description><link>https://www.rafaelquintanilha.com/converting-jupyter-notebooks-into-blog-posts-with-gatsby/</link><guid isPermaLink="false">63706c6c42a473003d9dcbbb</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Gatsby]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Mon, 05 Oct 2020 03:00:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/cover--1-.png" class="kg-image" alt loading="lazy" width="730" height="487" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/cover--1-.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/cover--1-.png 730w" sizes="(min-width: 720px) 720px"><figcaption>Converting Jupyter Notebooks Into Blog Posts With Gatsby</figcaption></figure><!--kg-card-begin: markdown--><p>Everyone acquainted with data science knows that Jupyter Notebooks are the way to go. They easily allow you to mix Markdown with actual code, creating a lively environment for research and learning. Code becomes user-friendly and nicely formatted &#x2014; write about it and generate dynamic charts, tables, and images on the go.</p>
<p>Writing Notebooks is so good that it is only natural to imagine that you might want to share them on the internet. Surely, you can host it in GitHub or even in <a href="https://colab.research.google.com/?ref=rafaelquintanilha.com">Google Colab</a>, but that will require a running kernel, and it&#x2019;s definitely not as friendly as a good ol&#x2019; webpage.</p>
<p>Before we go any further, it&#x2019;s important to understand that a Jupyter Notebook is nothing more than a collection of JSON objects containing inputs, outputs, and tons of metadata. It then constructs the outputs and can easily be <a href="https://github.com/jupyter/nbconvert/?ref=rafaelquintanilha.com">converted into different formats</a> (such as HTML).</p>
<p>Knowing that Notebooks can become an HTML document is all we need &#x2014; what remains is finding a way to automate this process so a <code>.ipynb</code> file can become a static page on the internet. My solution to this problem is to use GatsbyJS &#x2014; notably, one of the best static site generators out there, if not the single best.</p>
<p>Gatsby easily sources data from different formats &#x2014; JSON, Markdown, YAML, you name it &#x2014; and statically generates webpages that you can host on the world wide web. The final piece then becomes: instead of transforming Markdown into a post, do the same with a <code>.ipynb</code> file. The goal of this post is to walk you through this process.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="technical-challenges">Technical challenges</h2>
<p>A quick search on the web will show you <a href="https://www.gatsbyjs.com/plugins/@gatsby-contrib/gatsby-transformer-ipynb/?ref=rafaelquintanilha.com">gatsby-transformer-ipynb</a>. Basically, this is a Gatsby plugin that is able to parse the Notebook file in a way that we can access it later in our GraphQL queries. It&#x2019;s almost too good to be true!</p>
<p>And, in fact, it is. The hard work was done by the fine folks of <a href="https://github.com/nteract/nteract?ref=rafaelquintanilha.com">nteract</a>. However, the plugin hasn&#x2019;t been maintained in a while, and things don&#x2019;t simply work out of the box &#x2014; not to mention the lack of customization that one would expect from a plugin.</p>
<p>I&#x2019;ll spare you the boring stuff, but after fussing around the dark corners of GitHub, and with significant help from <a href="https://specific.solutions.limited/blog/rusty-jupyter/?ref=rafaelquintanilha.com">this post</a> by Specific Solutions, I managed to <a href="https://www.npmjs.com/package/@rafaelquintanilha/gatsby-transformer-ipynb?ref=rafaelquintanilha.com">create my own fork</a> of gatsby-transformer-ipynb, which solves my problems and will suffice for the purpose of this post.</p>
<p>Note, however, that I have no intention of become an active maintainer, and most of what I&#x2019;ve done was solely to get what I need to work &#x2014; use it at your own risk!</p>
<p>Enough with the preambles, let&#x2019;s get to some code.</p>
<h2 id="creating-a-project">Creating a project</h2>
<p>Firstly, the source code for what we are going to build can be <a href="https://github.com/rafaelquintanilha/jupyter-blog?ref=rafaelquintanilha.com">found here on GitHub</a>. We&#x2019;ll start by creating a Gatsby project. Make sure you have <a href="https://www.gatsbyjs.com/docs/quick-start/?ref=rafaelquintanilha.com">Gatsby installed</a>, and create a new project by running:</p>
<pre><code>gatsby new jupyter-blog
cd jupyter-blog
</code></pre>
<p>Run <code>gatsby develop</code> and go to <a href="http://localhost:8000/?ref=rafaelquintanilha.com">http://localhost:8000/</a> to make sure everything is working fine.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="create-your-first-notebook">Create your first Notebook</h2>
<p>Since Jupyter Notebooks will be the data source for our brand-new blog, we need to start adding content. Within your project folder, go to <code>src</code> and create a <code>notebooks</code> folder. We&#x2019;ll make sure to read from this folder later.</p>
<p>It&#x2019;s time to create our first Notebook. For the purposes of this tutorial, I&#x2019;ll use <a href="https://github.com/rafaelquintanilha/jupyter-blog/blob/master/src/notebooks/my-first-post.ipynb?ref=rafaelquintanilha.com">this simple Notebook</a> as a base. You can see the dynamic output in GitHub, but feel free to use whichever you want.</p>
<p>In any case, it&#x2019;s worth mentioning that some rich outputs such as dynamic charts generated by <a href="https://plotly.com/?ref=rafaelquintanilha.com">Plotly</a> may need extra care &#x2014; let me know if you want me to cover that in a later post! To keep this post short, however, we&#x2019;ll handle only static images, tables, and Markdown.</p>
<p>Now that you have a Gatsby project with data, the next step is to query it using GraphQL.</p>
<h2 id="querying-data">Querying data</h2>
<p>One of the biggest advantages of Gatsby is flexibility when sourcing data. Virtually anything you want can become a data source that can be used to generate static content.</p>
<p>As mentioned above, we&#x2019;ll be using my own version of the transformer. Go ahead and install it:</p>
<pre><code>yarn add @rafaelquintanilha/gatsby-transformer-ipynb
</code></pre>
<p>The next step is to configure the plugins. In <code>gatsby-config.js</code>, add the following to your <code>plugins</code> array (you can always <a href="https://github.com/rafaelquintanilha/jupyter-blog/blob/master/gatsby-config.js?ref=rafaelquintanilha.com">check GitHub</a> when in doubt):</p>
<pre><code class="language-jsx">...
{
  resolve: `gatsby-source-filesystem`,
  options: {
    name: `notebooks`,
    path: `${__dirname}/src/notebooks`,
    ignore: [`**/.ipynb_checkpoints`],
  },
},
{
  resolve: `@rafaelquintanilha/gatsby-transformer-ipynb`,
  options: {
    notebookProps: {
      displayOrder: [&quot;image/png&quot;, &quot;text/html&quot;, &quot;text/plain&quot;],
      showPrompt: false,
    },
  },
},
...
</code></pre>
<p>Let&#x2019;s break it down.</p>
<p>First, we add a <code>gatsby-source-filesystem</code> option in the array. We are telling Gatsby to look for files in <code>src/notebooks</code>, where our <code>.ipynb</code> files live. Next, we are configuring the transformer and setting some props:</p>
<ul>
<li><code>displayOrder</code> &#x2013; MIME type of the outputs we are displaying</li>
<li><code>showPrompt</code> &#x2013; whether the prompt is displayed</li>
</ul>
<p>While prompts make sense in Notebooks, in static pages, they lose their purpose. For that matter, we will hide them in order to have clear content.</p>
<p>Time to check whether everything went according to plan. Open GraphiQL by going to <a href="http://localhost:8000/___graphql?ref=rafaelquintanilha.com">http://localhost:8000/___graphql</a> and run the following query:</p>
<pre><code>query MyQuery {
  allJupyterNotebook {
    nodes {
      html
    }
  }
}
</code></pre>
<p>Success! Note how the HTML of our notebooks was generated. All that is left is to inject this HTML into a React component and our process will be complete.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="generating-posts-automatically">Generating posts automatically</h2>
<p>The worst is behind us now. The next step is to query this data in <code>gatsby-node.js</code> so we can generate static pages for each Notebook in <code>src/notebooks</code>.</p>
<p>Note, however, that we need to add additional metadata to our Notebook, e.g., author and post title. There are several ways of doing it, and the simplest is probably to take advantage of the fact that <code>.ipynb</code> files are JSON and use their own <code>metadata</code> field. Open the <code>.ipynb</code> and add the info you need:</p>
<pre><code class="language-json">{
 &quot;metadata&quot;: {
  &quot;author&quot;: &quot;Rafael Quintanilha&quot;,
  &quot;title&quot;: &quot;My First Jupyter Post&quot;,
  &quot;language_info&quot;: {
   &quot;codemirror_mode&quot;: {
    &quot;name&quot;: &quot;ipython&quot;,
    &quot;version&quot;: 3
   },
   &quot;file_extension&quot;: &quot;.py&quot;,
   &quot;mimetype&quot;: &quot;text/x-python&quot;,
   &quot;name&quot;: &quot;python&quot;,
   &quot;nbconvert_exporter&quot;: &quot;python&quot;,
   &quot;pygments_lexer&quot;: &quot;ipython3&quot;,
   &quot;version&quot;: &quot;3.7.4-final&quot;
  },
  &quot;orig_nbformat&quot;: 2,
  &quot;kernelspec&quot;: {
   &quot;name&quot;: &quot;python3&quot;,
   &quot;display_name&quot;: &quot;Python 3&quot;
  }
 },
 &quot;nbformat&quot;: 4,
 &quot;nbformat_minor&quot;: 2,
 &quot;cells&quot;: [
  ...
 ]
}
</code></pre>
<p><em><strong>Pro tip:</strong> If you&#x2019;re using VS Code, opening the file will probably launch the Jupyter kernel. You can disable it in the configs to edit the raw content, but I usually just open the file with another editor (such as gedit or Notepad++).</em></p>
<p>The process now is exactly the same for any data source with Gatsby. We&#x2019;ll query the data in <code>gatsby-node.js</code> and pass the relevant info to a post template, which, in turn, will become a unique page in our domain.</p>
<p>Before getting to that, however, open <code>gatsby-node.js</code> and add the following:</p>
<pre><code class="language-js">exports.onCreateNode = ({ node, actions }) =&gt; {
  const { createNodeField } = actions
  if (node.internal.type === &apos;JupyterNotebook&apos;) {
    createNodeField({
      name: &apos;slug&apos;,
      node,
      value: node.json.metadata.title
        .split(&apos; &apos;)
        .map(token =&gt; token.toLowerCase())
        .join(&apos;-&apos;),
    })
  }
}
</code></pre>
<p>The above excerpt will, for every node created in GraphQL, check those that are a Jupyter Notebook and extend them with a new field, <code>slug</code>. We are using a naive approach here, but you can use a robust library such as <a href="https://www.npmjs.com/package/slugify?ref=rafaelquintanilha.com">slugify</a>. The new field will be queried and used to generate the post path. In the same file, add the following:</p>
<pre><code class="language-jsx">const path = require(`path`)
exports.createPages = async ({ graphql, actions: { createPage } }) =&gt; {
  const blogPostTemplate = path.resolve(`src/templates/BlogPost.js`)
  const results = await graphql(
    `
      {
        allJupyterNotebook() {
          nodes {
            fields {
              slug
            }
          }
        }
      }
    `
  )
  const posts = results.data.allJupyterNotebook.nodes
  posts.forEach(post =&gt; {
    createPage({
      path: post.fields.slug,
      component: blogPostTemplate,
      context: {
        slug: post.fields.slug,
      },
    })
  })
}
</code></pre>
<p>This basically queries data by slug and sends them to <code>BlogPost.js</code>. Let&#x2019;s create it now:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import { graphql } from &apos;gatsby&apos;
import SEO from &apos;../components/seo&apos;

const BlogPost = ({
  data: {
    jupyterNotebook: {
      json: { metadata },
      html,
    },
  },
}) =&gt; {
  return (
    &lt;div&gt;
      &lt;SEO title={metadata.title} /&gt;
      &lt;h1&gt;{metadata.title}&lt;/h1&gt;
      &lt;p&gt;Written by {metadata.author}&lt;/p&gt;
      &lt;div dangerouslySetInnerHTML={{ __html: html }} /&gt;
    &lt;/div&gt;
  )
}
export default BlogPost
export const query = graphql`
  query BlogPostBySlug($slug: String!) {
    jupyterNotebook(fields: { slug: { eq: $slug } }) {
      json {
        metadata {
          title
          author
        }
      }
      html
    }
  }
`
</code></pre>
<p>And that&#x2019;s it! Hop over to <a href="http://localhost:8000/my-first-jupyter-post?ref=rafaelquintanilha.com">http://localhost:8000/my-first-jupyter-post</a> and see your Notebook as a static HTML page.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="improvements">Improvements</h2>
<p>As you can see, a lot can be improved upon in terms of styling and design. This is beyond the scope of this post, but as a hint, you can use CSS Modules to enhance the layout and remove unnecessary <em>stdout</em> (text output that you don&#x2019;t care about in a blog post). Create <code>BlogPost.module.css</code> and add the following:</p>
<pre><code class="language-css">.content {
  max-width: 900px;
  margin-left: auto;
  margin-right: auto;
  padding: 40px 20px;
}

.content :global(.nteract-display-area-stdout),
.content :global(.nteract-outputs &gt; .cell_display &gt; pre) {
  display: none;
}

.content :global(.nteract-outputs &gt; .cell_display &gt; img) {
  display: block;
}

.content :global(.input-container) {
  margin-bottom: 20px;
}

.content :global(.input-container pre.input) {
  border-radius: 10px !important;
  padding: 1em !important;
}
.content :global(.input-container code) {
  line-height: 1.5 !important;
  font-size: 0.85rem !important;
}

.content :global(.input-container code:empty) {
  display: none;
}

@media only screen and (max-width: 940px) {
  .content {
    max-width: 100%;
    padding-left: 20px;
    padding-right: 20px;
    box-sizing: border-box;
  }
}
</code></pre>
<p>Now go back to <code>BlogPost.js</code> and add the class to our div:</p>
<pre><code class="language-jsx">...
import css from &quot;./BlogPost.module.css&quot;
...
return (
  &lt;div className={css[&apos;content&apos;]}&gt;
     ...
  &lt;/div&gt;
);
</code></pre>
<p>Note how much cleaner it looks now. The final result (with minor tweaks) is hosted in <a href="https://jupyter-blog.netlify.app/?ref=rafaelquintanilha.com">Netlify</a>. All changes are in the <a href="https://github.com/rafaelquintanilha/jupyter-blog?ref=rafaelquintanilha.com">source code</a>.</p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>Transforming Jupyter Notebooks into HTML pages is not complicated but does involve a lot of small steps and adjustments. Hopefully, this post is a guide on how to get started with it.</p>
<p>There are tons of changes and improvements that can be done, like supporting rich outputs (such as a dynamic chart), improving the mobile experience, better metadata management, and more.</p>
<p>Notebooks are versatile and fun to work with, and automatically converting them into a webpage is a very nice feature of them.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[When React Hooks re-render components]]></title><description><![CDATA[Learn how hooks affect the component lifecycle, in which order they are called, and when they are executed.]]></description><link>https://www.rafaelquintanilha.com/when-react-hooks-re-render-components/</link><guid isPermaLink="false">63824cbc14168e003dd8f4f3</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 03 Jun 2020 17:55:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/12/post-hooks-guide-react-call-order.png" class="kg-image" alt loading="lazy" width="730" height="486" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/12/post-hooks-guide-react-call-order.png 600w, https://www.rafaelquintanilha.com/content/images/2022/12/post-hooks-guide-react-call-order.png 730w" sizes="(min-width: 720px) 720px"><figcaption>React Hooks call order</figcaption></figure><p>Since the introduction of Hooks in React 16.8, the way developers write their components has changed. Hooks arguably improve the developer experience and help you save time writing unnecessary code and boilerplate.</p><p>But in order to achieve such greatness, some abrupt changes were required. The well-established paradigm of class components was ditched, and lifecycle hooks, which semantically make a lot of sense, were removed.</p><p>It is vital to understand that there is no such thing as a 1:1 map between an old lifecycle hook and new React Hooks. Indeed, you can leverage them to achieve the same effect, but ultimately, they are not the same thing.</p><p>The goal of this article &#x2014; in addition to stressing that writing Hooks requires a different mindset than writing class components &#x2014; is to give you a better overview of how, exactly, the whole React component lifecycle works. That is to say, in what order the code is being executed in your app.</p><p>Even if you think you know the answer, bear with me. You might find surprising results throughout this text.</p><h2 id="the-basics"><strong>The basics</strong></h2><p>As always, let&#x2019;s start with the basics. React, as its name suggests, is reactive to changes &#x2014; namely, to changes in either its props or state. A prop is an external variable passed to a component, and a state is an internal variable that persists across multiple renders.</p><p>Both props and state variables cause a re-render when they change; from this, it follows that the only difference between a state and a ref is that a ref change does not cause a re-render. <a href="https://rafaelquintanilha.com/the-complete-guide-to-react-refs/?ref=rafaelquintanilha.com">More about refs here</a>.</p><p>Consider the following example:</p><pre><code class="language-javascript">const CustomButton = () =&gt; {
  console.log(&quot;I&apos;m always called&quot;);
  return &lt;button&gt;Click me&lt;/button&gt;;
}</code></pre><p>The above component has no props (arguments to the function, i.e., the component) and no state. This means that, as it stands, it will render only once.</p><p>Now, consider the version with a prop:</p><pre><code class="language-javascript">const CustomButton = ({color}) =&gt; {
  console.log(&quot;I&apos;m called with color&quot;, color);
  return &lt;button style={{color}}&gt;Click me&lt;/button&gt;;
}</code></pre><p>If you render <code>&lt;CustomButton color=&quot;red&quot; /&gt;</code> and then change it to <code>&lt;CustomButton color=&quot;blue&quot; /&gt;</code>, you will see two logs, one for each time the function (component) was called.</p><p>Let&#x2019;s now introduce the concept of state. Consider the whole application below:</p><pre><code class="language-javascript">const App = () =&gt; {
  const [count, setCount] = useCount(0);
  const buttonColor = count % 2 === 0 ? &quot;red&quot; : &quot;blue&quot;;
  console.log(&quot;I&apos;m called with count&quot;, count);
  return (
    &lt;div&gt;
      &lt;CustomButton color={buttonColor} onClick={() =&gt; setCount(count + 1)} /&gt;
      &lt;p&gt;Button was clicked {count} times&lt;/p&gt;
    &lt;/div&gt;
  );
}

const CustomButton = ({color, onClick}) =&gt; {
  console.log(&quot;I&apos;m called with color&quot;, color);
  return &lt;button style={{color}} onClick={onClick}&gt;Click me&lt;/button&gt;;
}</code></pre><p>Now we have a nested component. We shall study how it reacts in several scenarios, but for now, let&#x2019;s take a look at what happens when we mount <code>&lt;App /&gt;</code>, i.e., when the application is rendered:</p><!--kg-card-begin: html--><pre>
I&apos;m called with count 0
I&apos;m called with color &quot;red&quot;
</pre><!--kg-card-end: html--><p>If you click on the button once, note that the console output will include:</p><!--kg-card-begin: html--><pre>
I&apos;m called with count 1
I&apos;m called with color &quot;blue&quot;
</pre><!--kg-card-end: html--><p>And for a second click:</p><!--kg-card-begin: html--><pre>
I&apos;m called with count 2
I&apos;m called with color &quot;red&quot;
</pre><!--kg-card-end: html--><p>What is happening? Well, every time you click on the button, you change <code>App</code>&#x2018;s state. Because there was a state change (<code>count</code> was incremented), the component re-renders (the function runs again).</p><p>In this new execution, once <code>count</code> changes, <code>buttonColor</code> will also change. But note that <code>buttonColor</code> is passed as a prop to <code>CustomButton</code>. Once a prop changes, <code>CustomButton</code> will also re-render.</p><p>Before we dive deeper into Hooks, consider this extended version:</p><pre><code class="language-javascript">const App = () =&gt; {
  const [count, setCount] = useState(0);
  const buttonColor = count % 2 === 0 ? &quot;red&quot; : &quot;blue&quot;;
  console.log(&quot;I&apos;m called with count&quot;, count);
  render (
    &lt;div&gt;
      &lt;CustomButton color={buttonColor} onClick={() =&gt; setCount(count + 1)} /&gt;
      &lt;CustomButton color=&quot;red&quot; onClick={() =&gt; setCount(count + 1)} /&gt;
      &lt;p&gt;Button was clicked {count} times&lt;/p&gt;
    &lt;/div&gt;
  );
}

const CustomButton = ({color, onClick}) =&gt; {
  console.log(&quot;I&apos;m called with color&quot;, color);
  return &lt;button style={{color}} onClick={onClick}&gt;Click me&lt;/button&gt;;
}</code></pre><p>What do you think will happen now?</p><p>One fair observation would be to say that only the first <code>CustomButton</code>, which has a variable color, will change. However, that&#x2019;s not what we see in practice: both buttons will re-render. In this particular case, <code>onClick</code> changes whenever <code>count</code> changes, and as we saw, a prop change will trigger a re-render.</p><p>We shall see, however, that having static props and state alone aren&#x2019;t enough to prevent a re-render.</p><h2 id="understanding-re-renders"><strong>Understanding re-renders</strong></h2><p>Consider the following example:</p><pre><code class="language-javascript">const App = () =&gt; {
  const [count, setCount] = useCount(0);
  console.log(&quot;I&apos;m called with count&quot;, count);
  render (
    &lt;div&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;Increment&lt;/button&gt;
      &lt;p&gt;Button was clicked {count} times&lt;/p&gt;
      &lt;StaticComponent /&gt;
    &lt;/div&gt;
  );
}

const StaticComponent = () =&gt; {
  console.log(&quot;I&apos;m boring&quot;);
  return &lt;div&gt;I am a static component&lt;/div&gt;;
}</code></pre><p>Notice that <code>StaticComponent</code> has neither props nor state. Considering what we learned so far, one might imagine that it will render only once, and never re-render even if the parent <code>App</code> changes. Again, in practice, that&#x2019;s not what happens, and <code>I&apos;m boring</code> will be logged in the console every time the button is clicked. What&#x2019;s going on?</p><p>Turns out that React re-renders every child of the tree whose parent is the component that changed. In other words, if A is the parent of B, and B is the parent of C, a change in B (e.g., a state variable being updated) will spare A from change but will re-render both B and C.</p><p>The following image from this <a href="https://blog.10pines.com/2018/08/27/reactjs-virtual-dom/?ref=rafaelquintanilha.com">great post by Ornella Bordino</a> gives a good visual of the effect:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/dom-tree-visualization.webp" class="kg-image" alt loading="lazy" width="670" height="240" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/dom-tree-visualization.webp 600w, https://www.rafaelquintanilha.com/content/images/2022/11/dom-tree-visualization.webp 670w"><figcaption>DOM tree visualization</figcaption></figure><p>Refer to the above post if you are interested in the implementation details.</p><p>The ingenuous reader is now asking: Is that a way to prevent this behavior? The answer, as you might expect, is yes. React has a <a href="https://reactjs.org/docs/react-api.html?ref=rafaelquintanilha.com#reactmemo">built-in function called <code>memo</code></a> that basically memoizes the result of the component and prevents the re-render given that neither the props nor state change.</p><p>We could update the prior example to:</p><pre><code class="language-javascript">...
const StaticComponent = React.memo(() =&gt; {
  console.log(&quot;I&apos;m boring&quot;);
  return &lt;div&gt;I am a static component&lt;/div&gt;;
});</code></pre><p>&#x2026;and voil&#xE0;! Our <code>StaticComponent</code> will render only once and never re-render, no matter what happens up in the tree.</p><p>A word of caution: React.memo should be used sparingly. Truth is, you may never need to use it at all! Its benefits will only show up for components that are large (so re-rendering them often is undesirable) and mostly static (because you do not want to make shallow comparisons every time). <a href="https://dmitripavlutin.com/use-react-memo-wisely/?ref=rafaelquintanilha.com">Use </a><code><a href="https://dmitripavlutin.com/use-react-memo-wisely/?ref=rafaelquintanilha.com">React.memo()</a></code><a href="https://dmitripavlutin.com/use-react-memo-wisely/?ref=rafaelquintanilha.com"> wisely</a> is a fine piece that describes exactly when this technique should or should not be used.</p><p>The following CodeSandbox wraps up our discussion about re-rendering. Notice that having <code>React.memo()</code> only prevents a re-render when the props won&#x2019;t:</p><!--kg-card-begin: html--><iframe src="https://codesandbox.io/embed/re-render-and-reactmemo-6crdv?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="Re-render and React.memo()" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"></iframe><!--kg-card-end: html--><blockquote><strong>Note</strong>: As of the time of this writing, there&#x2019;s a bug in CodeSandbox when the component is called twice when there is a state change. In a production environment, this won&#x2019;t happen.</blockquote><h2 id="call-order"><strong>Call order</strong></h2><p>Now that we have a clear understanding of when components (functions) are rendered (executed) in React, we are ready to investigate the order in which they are called. Consider the following example:</p><pre><code class="language-javascript">const Internal = () =&gt; {
  console.log(&quot;I&apos;m called after&quot;)
  return &lt;div&gt;Child Component&lt;/div&gt;
}

const App = () =&gt; {
  console.log(&quot;I&apos;m called first&quot;);
  return (
    &lt;Internal /&gt;
  );
}</code></pre><p>As you might expect, the console will log:</p><!--kg-card-begin: html--><pre>
I&apos;m called first
I&apos;m called after
</pre><!--kg-card-end: html--><p>Now, we know that <code>useEffect</code> Hooks are called after the component is mounted (<a href="https://rafaelquintanilha.com/how-to-reuse-logic-with-react-hooks/?ref=rafaelquintanilha.com#useeffect">more about <code>useEffect</code> here</a>). What do you expect will be the log for the following?</p><pre><code class="language-javascript">const Internal = () =&gt; {
  console.log(&quot;I&apos;m called after&quot;)

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called after Internal mounts&quot;);
  });
  return &lt;div&gt;Child Component&lt;/div&gt;
}

const App = () =&gt; {
  console.log(&quot;I&apos;m called first&quot;);

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called after App mounts&quot;);
  });
  return (
    &lt;Internal /&gt;
  );
}</code></pre><p>Surprisingly:</p><!--kg-card-begin: html--><pre>
I&apos;m called first
I&apos;m called after
I&apos;m called after Internal mounts
I&apos;m called after App mounts
</pre><!--kg-card-end: html--><p>This happens because <code>useEffect</code> is called in a bottom-up fashion, so the effects resolve first in the children, and then in the parent.</p><p>What do you think will happen if we add a callback ref?</p><pre><code class="language-javascript">const Internal = () =&gt; {
  console.log(&quot;I&apos;m called after&quot;)

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called after Internal mounts&quot;);
  });
  return &lt;div&gt;Child Component&lt;/div&gt;
}

const App = () =&gt; {
  console.log(&quot;I&apos;m called first&quot;);

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called after App mounts&quot;);
  };
  return (
    &lt;Internal ref={ref =&gt; console.log(&quot;I&apos;m called when the element is in the DOM&quot;)} /&gt;
  );
}</code></pre><p>The result:</p><!--kg-card-begin: html--><pre>
I&apos;m called first
I&apos;m called after
I&apos;m called when the element is in the DOM
I&apos;m called after Internal mounts
I&apos;m called after App mounts
</pre><!--kg-card-end: html--><p>This is tricky but important: it tells us when we can expect to access an element in the DOM, and the answer is after components are rendered but before the effects run.</p><h2 id="useeffect-order"><strong><code>useEffect</code> order</strong></h2><p>We have seen that <code>useEffect</code> runs after the component mounts. But in which order are they called?</p><pre><code class="language-javascript">const App = () =&gt; {
  console.log(&quot;I&apos;m called first&quot;);

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called third&quot;);
  };

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called fourth&quot;);
  };

  console.log(&quot;I&apos;m called second&quot;);

  return (
    &lt;div&gt;Hello&lt;/div&gt;
  );
}</code></pre><p>No surprises here. Everything outside the effects will run first, and then the effects will be called in order. Notice that <code>useEffect</code><a href="https://reactjs.org/docs/hooks-effect.html?ref=rafaelquintanilha.com#tip-optimizing-performance-by-skipping-effects">accepts a dependency array</a>, which will trigger the effect when the component first mounts and when any of the dependencies change.</p><pre><code class="language-javascript">const App = () =&gt; {
  const [count, setCount] = useState(0);
  const [neverIncremented, _] = useState(0);
  console.log(&quot;I&apos;m called first&quot;);

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called second on every render&quot;);
  };

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called only during the first render&quot;);
  }, [];

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called during the first render and whenever count changes&quot;);
  }, [count];

  const useEffect(() =&gt; {
    console.log(&quot;I&apos;m called during the first render and whenever neverIncremented changes&quot;);
  }, [neverIncremented];

  return (
    &lt;div&gt;
      &lt;p&gt;Count is {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Click to increment
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>If you run the above code, the output will be:</p><!--kg-card-begin: html--><pre>
I&apos;m called first
I&apos;m called second on every render
I&apos;m called only during the first render
I&apos;m called during the first render and whenever count changes
I&apos;m called during the first render and whenever neverIncremented changes
</pre><!--kg-card-end: html--><p>Finally, if you click on the button:</p><!--kg-card-begin: html--><pre>
I&apos;m called first
I&apos;m called second on every render
I&apos;m called during the first render and whenever count changes
</pre><!--kg-card-end: html--><h2 id="a-word-of-caution-with-callback-refs"><strong>A word of caution with callback refs</strong></h2><p>Callback refs can have unexpected behavior. We&#x2019;ve seen before that they are called between components rendering and effects running. But there&#x2019;s a special case when the component is updated:</p><pre><code class="language-javascript">const App = () =&gt; {
  const [count, setCount] = useState(0);

  console.log(&quot;I&apos;m called first&quot;);

  return (
    &lt;div&gt;
      &lt;p&gt;Count is {count}&lt;/p&gt;
      &lt;button 
        onClick={() =&gt; setCount(count + 1)}
        ref={ref =&gt; {
          console.log(&quot;I&apos;m called second with ref&quot;, ref);
        }}&gt;
        Click to increment
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>When the component first renders, the output will be:</p><!--kg-card-begin: html--><pre>
I&apos;m called first 
I&apos;m called second with ref <button>Click to increment</button>
</pre><!--kg-card-end: html--><p>Which is precisely what you expect. Now check what happens when you click on the button and trigger a re-render:</p><!--kg-card-begin: html--><pre>
I&apos;m called first 
I&apos;m called second with ref null
I&apos;m called second with ref <button>Click to increment</button>
</pre><!--kg-card-end: html--><p>The callback is executed twice, and the worst thing about it is that the ref is <code>null</code> during the first execution! This is a common source of bugs when users programatically want to trigger some DOM interaction when the state changes (for example, calling <code>ref.focus()</code>). <a href="https://rafaelquintanilha.com/the-complete-guide-to-react-refs/?ref=rafaelquintanilha.com#deciding-between-callback-refs-and-createref">Check out a more detailed explanation here</a>.</p><p>The following CodeSandbox summarizes what was explained in the previous sections:</p><!--kg-card-begin: html--><iframe src="https://codesandbox.io/embed/call-order-i25gk?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="Call Order" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"></iframe><!--kg-card-end: html--><h2 id="conclusion"><strong>Conclusion</strong></h2><p>React Hooks are great, and their implementation is straightforward. However, mastering a component&#x2019;s lifecycle is not trivial, especially because old lifecycle hooks were deprecated. With patience, however, one can understand exactly what is going on in a React tree and even optimize if it ever comes to be a problem.</p><p>Personally, I have been working exclusively with the Hooks API since its first release and still find myself confused from time to time. Hopefully, this article will serve as a guide not only to me but to you as you get more comfortable and experienced with the marvelousness of Hooks.</p>]]></content:encoded></item><item><title><![CDATA[Writing Tests as User Stories in React]]></title><description><![CDATA[A mental model for designing UI tests.]]></description><link>https://www.rafaelquintanilha.com/writing-tests-as-user-stories-in-react/</link><guid isPermaLink="false">63706b6742a473003d9dcb9e</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[React Testing Library]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Best Practices]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Thu, 02 Apr 2020 03:00:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/cover.png" class="kg-image" alt loading="lazy" width="730" height="412" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/cover.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/cover.png 730w" sizes="(min-width: 720px) 720px"><figcaption>Writing tests as user stories</figcaption></figure><!--kg-card-begin: markdown--><p>Testing code can be a controversial subject, largely due to the multitude of ways one can go about writing a test.</p>
<p>There are no clear rules, and ultimately you are the one in charge of deciding what&#x2019;s worth testing and how you&#x2019;re going to do it.</p>
<p>One common mistake is to test implementation details, but perhaps you&#x2019;ve read that already.</p>
<p>Let me take a step back then &#x2014; what is the end goal of a test?</p>
<h2 id="writing-user-stories">Writing user stories</h2>
<p>A common software abstraction is to write user stories &#x2014; that is, possible actions that a user can take when interacting with your application.</p>
<p>Suppose you are to build a Celsius-to-Fahrenheit converter. A legitimate story could be something like:</p>
<p><em>&#x201C;As a user, I want to be able to convert from Celsius to Fahrenheit.&#x201D;</em></p>
<p>Naturally, as a careful developer, you want to assert that for a given set of numbers and inputs the conversion works (or it fails gracefully for invalid inputs like &#x201C;banana&#x201D;).</p>
<p>Note, however, that testing that a function is able to successfully handle the conversion from Celsius to Fahrenheit is only half the story.</p>
<p>If you are able to perform the most expensive and relevant calculation but your end user can&#x2019;t access it, all effort will be in vain.</p>
<p>Why is that?</p>
<p>Well, as a frontend developer, your job is to not only ensure users get the correct answers to their questions but also to make sure they can use your application.</p>
<p>Therefore, you need to assess that the user has interacted with your application as expected.</p>
<p>In our example, that means that somewhere on the screen you expect some text to be displayed like this: &#x201C;25&#xBA;C equals 77&#xBA;F.&#x201D;</p>
<p>Now, that&#x2019;s a relevant test. You just assessed that, for a given input, the user satisfactorily got the right answer on the screen.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="stories-mostly-don%E2%80%99t-care-about-details">Stories (mostly) don&#x2019;t care about details</h2>
<p>The main takeaway here is that the user stories aren&#x2019;t centered on your development implementations, so your tests shouldn&#x2019;t be, either.</p>
<p>Of course, the scenarios in question are related to application-wide tests (things that have context), not bare-bones libraries.</p>
<p>If your goal is to create a library that converts Celsius to Fahrenheit to Kelvin, then it&#x2019;s fine to test the details once you are detached of context.</p>
<p>Now that we understand that tests should resemble user stories, you can predict where semantics come from.</p>
<p>At the end of the day, your tests should have clear semantics such that you could read them in plain English&#x2014;the same way you describe user stories.</p>
<p>We&#x2019;ll see how we can leverage the <a href="https://github.com/testing-library/react-testing-library?ref=rafaelquintanilha.com">React Testing Library API</a> to write semantic tests that make sense.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="case-study-temperature-converter">Case study: Temperature Converter</h2>
<p>Let&#x2019;s dive further into the Temperature Converter application.</p>
<p>We&#x2019;ll pretend that a competent Project Manager heard the complaints of their clients (probably any non-American who has moved recently to the US) and came up with the following requirements:</p>
<ul>
<li>As a user, I want to be able to convert from Celsius to Fahrenheit</li>
<li>As a user, I want to be able to convert from Fahrenheit to Celsius</li>
<li>As a user, I want to click on a Reset button so I can easily convert many values with minimal effort</li>
</ul>
<p>Apart from the lack of creativity of the PM when writing stories, the requirements are pretty straightforward.</p>
<p>We will sketch a simple app, do a good ol&#x2019; smoke test to check that everything looks alright, and then apply what we just learned in order to write better tests.</p>
<p>Consider the following CodeSandbox for our sample application:<br>
<a href="https://codesandbox.io/s/temperature-converter-mw7se?ref=rafaelquintanilha.com">https://codesandbox.io/s/temperature-converter-mw7se</a></p>
<p>Diving into the specifics of the code is beyond the scope of this article (check <a href="https://rafaelquintanilha.com/how-to-reuse-logic-with-react-hooks?ref=rafaelquintanilha.com">&#x201C;How to Reuse Logic With React Hooks</a>&#x201D; for more context on how to use Hooks to create React applications).</p>
<p>However, the code should be pretty straightforward. We are basically requiring user input and allowing them to convert from Celsius to Fahrenheit or vice-versa.</p>
<p>We then display the results and a Reset button shows up. Upon clicking the button, the input is cleared and regains focus.</p>
<p>This aligns with what our users are looking for: we&#x2019;ll improve the usability of the app and, most importantly, preserve its accessibility.</p>
<p>Now that we have a live application that seems to work, let&#x2019;s be responsible developers and write some tests.</p>
<p>We&#x2019;ll try to match each user story to a single test. By doing that, we will be confident that each requirement is being fulfilled with a set of tests backing us up.</p>
<p>Consider this basic skeleton for <code>App.test.js</code>:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import { cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

test(&apos;user is able to convert from celsius to fahrenheit&apos;, () =&gt; {
  /* story 1 goes here */
})

test(&apos;user is able to convert from fahrenheit to celsius&apos;, () =&gt; {
  /* story 2 goes here */
})

test(&apos;user can reset calculation and automatically focus on the input&apos;, () =&gt; {
  /* story 3 goes here */
})
</code></pre>
<p>(We are using <a href="https://jestjs.io/?ref=rafaelquintanilha.com">Jest</a> as our test runner, but that&#x2019;s not relevant to the main point presented in the article.)</p>
<p>Notice that our three tests are really straightforward and any failures in them would quickly expose what is really going on.</p>
<p>Now we&#x2019;ll leverage RTL and write the first test in a way that makes sense:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import App from &apos;./App.js&apos;
import { cleanup, render, screen } from &apos;@testing-library/react&apos;
import userEvent from &apos;@testing-library/user-event&apos;

afterEach(cleanup)

test(&apos;user is able to convert from celsius to fahrenheit&apos;, () =&gt; {
  render(&lt;App /&gt;)
  const input = screen.getByLabelText(&apos;Temperature:&apos;)
  userEvent.type(input, &apos;25&apos;)
  expect(screen.getByText(&apos;25&#xBA;C equals to 77&#xBA;F&apos;)).toBeTruthy()
  userEvent.type(input, &apos;0&apos;)
  expect(screen.getByText(&apos;0&#xBA;C equals to 32&#xBA;F&apos;)).toBeTruthy()
  userEvent.type(input, &apos;banana&apos;)
  expect(screen.queryByTestId(&apos;result&apos;)).toBeFalsy()
})

/* code goes on */
</code></pre>
<p>There are a couple of things to notice with the dependencies:</p>
<p>First, we import the component in question <code>App.js</code>.</p>
<p>Then, notice that we are importing <code>render</code> and <code>screen</code> from RTL. While the first has been around since the library&#x2019;s first launch, <code>screen</code> is a new addition <a href="https://github.com/testing-library/react-testing-library/releases/tag/v9.4.0?ref=rafaelquintanilha.com">shipped on version 9.4.0</a>. We will see its main advantage shortly.</p>
<p>We also import a new dependency, <a href="https://github.com/testing-library/user-event?ref=rafaelquintanilha.com">userEvents</a>, straight from <code>@testing-library/user-event</code>. This library will boost our test readability and help us achieve our goal of improving our semantics.</p>
<p>Let&#x2019;s actually dive into the test. If you are used to RTL, the first thing you&#x2019;ll notice is that <code>render</code> is not returning anything. In fact, that&#x2019;s the main advantage of importing <code>screen</code>.</p>
<p>What <code>screen</code> does is basically expose all queries that allow you to select elements in the screen (hence the name).</p>
<p>This is a pretty good change because it helps you avoid bloating the test with lots of <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment?ref=rafaelquintanilha.com">destructuring</a>, which is always annoying when you are not sure yet which queries to use.</p>
<p>Also, the code looks cleaner. (Note: there&#x2019;s still a case for de-structuring <code>container</code> and <code>rerender</code> as mentioned by Kent C. Dodds <a href="https://twitter.com/kentcdodds/status/1224790664354779136?ref=rafaelquintanilha.com">in this tweet</a>.)</p>
<p>The other difference from conventional tests you might have been writing is the <code>userEvent</code> object.</p>
<p>This object provides a handful of user interactions that are semantically understandable and conceal implementation details. Consider the following example:</p>
<pre><code class="language-jsx">// Previously
fireEvent.change(input, { target: { value: &apos;25&apos; } })

// With userEvents
userEvent.type(input, &apos;25&apos;)
</code></pre>
<p>Not only is our code is shorter, but it also makes much more sense now.</p>
<p>Remember that our goal is to write a test as close as possible to plain English. By encapsulating implementation details, <code>userEvent</code> really puts us on the right track.</p>
<p>If you are curious, <a href="https://github.com/testing-library/user-event?ref=rafaelquintanilha.com">go ahead and check their documentation</a>.</p>
<p>Once we are able to fill the input, we can now assert that the correct text is being displayed.</p>
<p>Now we can test a bunch of other options and confirm that what is displayed in the screen is expected (e.g., an invalid input like <code>banana</code> won&#x2019;t work).</p>
<p>Note: in a modular application, the conversion functions could be extracted in their own file and have their own tests (with many more test scenarios).</p>
<p>If you test the function separately, there&#x2019;s no need to make redundant checks in the user stories as well (test is code and you want it maintainable as such).</p>
<p>With a test that is only eight lines long, we were able to check that our first scenario works as expected.</p>
<p>Let&#x2019;s jump into our second user story &#x2014; convert from Fahrenheit to Celsius (maybe a New Yorker having some fun on a beach in South America).</p>
<p>The test should be pretty similar to our first one, with a single caveat: we need to make sure that the user has selected the right option.</p>
<pre><code class="language-jsx">test(&apos;user is able to convert from fahrenheit to celsius&apos;, () =&gt; {
  render(&lt;App /&gt;)
  const fahrenheitOption = screen.getByLabelText(&apos;Fahrenheit to Celsius&apos;)
  userEvent.click(fahrenheitOption)
  const input = screen.getByLabelText(&apos;Temperature:&apos;)
  userEvent.type(input, &apos;77&apos;)
  expect(screen.getByText(&apos;77&#xBA;F equals to 25&#xBA;C&apos;)).toBeTruthy()
  userEvent.type(input, &apos;32&apos;)
  expect(screen.getByText(&apos;32&#xBA;F equals to 0&#xBA;C&apos;)).toBeTruthy()
  userEvent.type(input, &apos;banana&apos;)
  expect(screen.queryByTestId(&apos;result&apos;)).toBeFalsy()
})
</code></pre>
<p>That&#x2019;s it. By leveraging <code>userEvent</code> again, emulating a click event becomes trivial.</p>
<p>Our code is perfectly readable and guarantees that the reverse direction (F to C) works as expected.</p>
<p>Our third and final test is slightly different &#x2014; now our goal is to test the user experience rather than whether or calculator works.</p>
<p>We want to make sure that our application is accessible and that users can rapidly test several values:</p>
<pre><code class="language-jsx">test(&apos;user can reset calculation and automatically focus on the input&apos;, () =&gt; {
  render(&lt;App /&gt;)
  const input = screen.getByLabelText(&apos;Temperature:&apos;)
  userEvent.type(input, &apos;25&apos;)
  expect(screen.queryByTestId(&apos;result&apos;)).toBeTruthy()
  const resetButton = screen.getByText(&apos;Reset&apos;)
  userEvent.click(resetButton)
  expect(screen.queryByTestId(&apos;result&apos;)).toBeFalsy()
  expect(document.activeElement).toBe(input)
})
</code></pre>
<p>There you have it. We basically made three checks:</p>
<ul>
<li>Whenever a user adds some input, there&#x2019;s a result displayed (the actual message shown is omitted from the test once this isn&#x2019;t what is being checked here)</li>
<li>When the Reset button is clicked, the result is not there anymore</li>
<li>The focus on the screen is back to the input</li>
</ul>
<p>One of my favorite things about RTL is how easy it is to assert where a focus really is.</p>
<p>Notice how semantic <code>expect(document.activeElement).toBe(input)</code> is. That pretty much looks like plain English to me.</p>
<p>And that&#x2019;s it. Our three stories are covered, the Project Manager is happier, and hopefully our tests will keep the code clean for a long time.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The aim of this article was to expose the recent modifications in the React Testing Library&#x2019;s API and show you how you can explore it to write better tests for you and your team.</p>
<p>I feel way more confident when I write tests that I understand because I stop chasing meaningless metrics (e.g. code coverage) to pay attention to what really matters (e.g. if my designed scenario works as expected).</p>
<p>React Testing Library was a big step in the right direction, mainly if you have some Enzyme background (in which case you might want to check &#x201C;<a href="https://rafaelquintanilha.com/react-testing-library-common-scenarios/?ref=rafaelquintanilha.com">React Testing Library Common Scenarios</a>,&#x201D; where I explore how you tackle everyday scenarios in a React application).</p>
<p>It really facilitates testing what your application should do rather than how it does it. The semantics make a difference.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Fixing Gatsby’s rehydration issue]]></title><description><![CDATA[Learn what a rehydration issue is in Gatsby, and the proper way to fix it.]]></description><link>https://www.rafaelquintanilha.com/fixing-gatsbys-rehydration-issue/</link><guid isPermaLink="false">638229c914168e003dd8f44f</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[Gatsby]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Fri, 20 Mar 2020 14:59:00 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-cover.webp" class="kg-image" alt loading="lazy" width="730" height="412" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/gatsby-cover.webp 600w, https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-cover.webp 730w" sizes="(min-width: 720px) 720px"><figcaption>Gatsby cover</figcaption></figure><p>If you have been developing Gatsby applications recently, it is likely that this has bitten you at some point.</p><p>Consider the following scenario: your application stores some information in the client (the user&#x2019;s browser), possibly in the <a href="https://developer.mozilla.org/en/docs/Web/API/Window/localStorage?ref=rafaelquintanilha.com" rel="noopener noreferrer">Local Storage</a>.</p><p>The goal is straightforward &#x2014; you want to quickly make UI changes based on individual data (e.g. theme preference, log-in details, etc).</p><p>You set everything up properly and it works locally, but as soon as you do the deploy things don&#x2019;t look quite like what you expected.</p><p>What happened?</p><p>This is what we call a <strong>rehydration issue</strong>.</p><p>In other words, React and Gatsby are having trouble matching data that came from the server with the change you want to do in the client.</p><p>This happens because <a href="https://reactjs.org/docs/react-dom.html?ref=rafaelquintanilha.com#hydrate" rel="noopener noreferrer">React does not expect</a> any mismatches between what was statically generated in the server and what was rendered by the client.</p><p>Before we dive deeper into what is going on, let&#x2019;s first go over how Gatsby works.</p><h2 id="server-side-rendering"><strong>Server-side rendering</strong></h2><p>Gatsby has a magnificent set of server-side rendering (SSR) features.</p><p>That means that it is able to render complex pages in the server and send the full output (a compiled file) to the client (your browser).</p><p>This contrasts with regular React applications (such as the ones created by Create React App), which are completely generated in the client, i.e., everything you see on the page is dynamically created after the JavaScript is downloaded, parsed, and evaluated.</p><p>With SSR, you already send the rendered content.</p><p>The end result is that your page loads really fast.</p><p>Cool, huh?</p><p>In a typical client-server exchange in an application powered by Gatsby, the page is retrieved first and the JavaScript is evaluated later.</p><p>It allows for quicker page loads, <a href="https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive?ref=rafaelquintanilha.com" rel="noopener noreferrer">TTI values</a>, faster <a href="https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint?ref=rafaelquintanilha.com" rel="noopener noreferrer">first meaningful paint</a>, and several other performance metrics. By the time your JavaScript is ready to come into play, a lot has already happened on your user&#x2019;s screen. Magic!</p><p>However, as you may have guessed, this has a caveat &#x2014; if your page is server-side rendered, but you need information that is available only to the client to complete the UI, you have a lacuna.</p><p>Suppose that you need to display a login button for a visitor and a logout button for a user.</p><p>If the information that the user is logged in (for example, a token stored in the Local Storage) is in the client only, how can the server-side rendered page know which button to display before the JavaScript loads?</p><p>In fact, if the user is already logged in, you will experience an annoying event &#x2014; the page will first display the login button (for there is no token available in the server whatsoever), and then it will revert to the logout button (as soon as the JavaScript code is evaluated and the token retrieved from the Local Storage).</p><p>This is annoying, but not the end of the world. It gets worse, though.</p><p>Suppose that the two buttons are in the same DOM tree and are conditionally rendered based on the information stored in the Local Storage.</p><p>Suppose also that they have different colors.</p><p>It is possible that their styles will be mixed up and you will end up with different colors than expected!</p><p>This is the end consequence of the so-called rehydration issue, where React will have trouble rehydrating the existing server-side rendered DOM with the dynamic content generated by the client.</p><p><a href="https://github.com/gatsbyjs/gatsby/issues/17914?ref=rafaelquintanilha.com" rel="noopener noreferrer">This is a problem that has been troubling Gatsby&#x2019;s users for a while now</a>. Fortunately, there is a simple way to overcome this problem and we&#x2019;ll explore it.</p><h2 id="the-rationale"><strong>The rationale</strong></h2><p>As we&#x2019;ve seen, this problem occurs because there is a mismatch between what the server renders and what the client generates.</p><p>We can mitigate this issue by holding off the particular element from rendering until we know for sure the client has fully loaded.</p><p>Bottom line is: why request the server to render if you can only guarantee the integrity after the client has acted?</p><p>Of course, you are looking at smaller pieces of UI, not a whole page, which would contradict the whole point of having SSR in the first place.</p><p>In fact, if you see yourself having this dilemma for a big chunk of your page, chances are you want to make it a <a href="https://www.gatsbyjs.org/docs/client-only-routes-and-user-authentication/?ref=rafaelquintanilha.com" rel="noopener noreferrer">client-only page</a> instead of serving it directly from the server.</p><h3 id="deferring-to-the-client"><strong>Deferring to the client</strong></h3><p>Now that we understand that we don&#x2019;t need to render the element until the client has loaded, how can we implement it? Fortunately, there is a very elegant way of doing it with React Hooks.</p><pre><code class="language-javascript">import React, { useState, useEffect } from &apos;react&apos;;

const Component = () =&gt; {
  const [isClient, setClient] = useState(false);

  useEffect(() =&gt; {
    setClient(true);
  }, []);

  return &lt;div&gt;I am in the {isClient ? &quot;client&quot; : &quot;server&quot;}&lt;/div&gt;;
}</code></pre><p>The above Hook leverages <code>useEffect</code> in order to correctly detect whether the user is in the server or in the client.</p><p>The logic is as follows &#x2014; <code>useEffect</code> with an empty dependency array runs only after the first render is committed to the screen (you can read more about it in the <a href="https://reactjs.org/docs/hooks-reference.html?ref=rafaelquintanilha.com#useeffect" rel="noopener noreferrer">documentation</a>).</p><p>If you are on the server, there is no screen at all. As a result, the effect never runs and <code>isClient</code> will be always <code>false</code>.</p><p>On the other hand, for any application rendered in the client, after the first render, the effect will run and <code>isClient</code> will become <code>true</code>.</p><p>This simple snippet is enough for us to detect where the code is being run.</p><p>However, it doesn&#x2019;t solve the potential issue with rehydration.</p><p>Consider the component below:</p><pre><code class="language-css">.red {
    color: red;
}
    
.blue {
    color: blue;
}</code></pre><pre><code class="language-javascript">const Component = () =&gt; {
    const [token, setToken] = useLocalStorage(&apos;token&apos;, &quot;&quot;);
    const isLoggedIn = token !== &quot;&quot;;
    
    /* Generate some fake token */
    const onLogin = () =&gt; setToken(Math.random().toString(36).substring(2));
    const onLogout = () =&gt; setToken(&quot;&quot;);
    
    return (
        &lt;div&gt;
        {isLoggedIn 
         ? &lt;button className={css[&apos;red&apos;]} onClick={onLogout}&gt;Logout&lt;/button&gt;
    	 : &lt;button className={css[&apos;blue&apos;]} onClick={onLogin}&gt;Login&lt;/button&gt;}
        &lt;/div&gt;
    );
}}</code></pre><p>Now we are retrieving a token from the Local Storage (you can check how to do it with a Hooks approach <a href="https://usehooks.com/useLocalStorage/?ref=rafaelquintanilha.com" rel="noopener noreferrer">here</a>) and rendering different components based on that information.</p><p>Due to the hydration issue, when the server first delivers the page to you, if you are logged in, you are going to see a blue Logout button!</p><p>Good luck debugging why this simple code isn&#x2019;t working only in production.</p><p>Drama aside, now that we identified the problem, how can we solve it?</p><p>Well, the key is to use the <code>key</code> prop of the component.</p><p>In simpler terms, <code>key</code> tells React that whenever it changes, the component needs to re-render.</p><p>The updated version of the code becomes:</p><pre><code class="language-javascript">const Component = () =&gt; {
      const [token, setToken] = useLocalStorage(&apos;token&apos;, &quot;&quot;);
      const isLoggedIn = token !== &quot;&quot;;
      
      /* Generate some fake token */
      const onLogin = () =&gt; setToken(Math.random().toString(36).substring(2));
      const onLogout = () =&gt; setToken(&quot;&quot;);
    
      return (
        &lt;div&gt;
          {isLoggedIn 
            ? &lt;button className={css[&apos;red&apos;]} onClick={onLogout}&gt;Logout&lt;/button&gt;
            : &lt;button className={css[&apos;blue&apos;]} onClick={onLogin}&gt;Login&lt;/button&gt;}
        &lt;/div&gt;
      );
    }}</code></pre><p>Note that <code>key</code> changes when the component detects it now runs on the client, forcing the element to re-render and apply the correct style (adapted from <a href="https://github.com/gatsbyjs/gatsby/issues/14601?ref=rafaelquintanilha.com#issuecomment-499922794" rel="noopener noreferrer">this comprehensive reply gave by Dustin Schau in GitHub</a>.)</p><p>Yet this only solves half of the problem.</p><p>Our styling mismatch issue was fixed, but there is still an annoying flickering due to the fact that the server renders first and then the client comes in and does its change.</p><p>Unfortunately, there is no way of fixing it without resorting to somehow letting the server knows beforehand if the user is logged in or not. However, a simple approach is to prevent the element from rendering at all whenever you detect that it is fully usable only in the client.</p><pre><code class="language-javascript">const Component = () =&gt; {
  const [isClient, setClient] = useState(false);
  const key = isClient ? &quot;client&quot; : &quot;server&quot;;
    
  const [token, setToken] = useLocalStorage(&apos;token&apos;, &quot;&quot;);
  const isLoggedIn = token !== &quot;&quot;;
      
  /* Generate some fake token */
  const onLogin = () =&gt; setToken(Math.random().toString(36).substring(2));
  const onLogout = () =&gt; setToken(&quot;&quot;);
    
  useEffect(() =&gt; {
    setClient(true);
  }, []);
    
  if ( !isClient ) return null;
  return (
    &lt;div key={key}&gt;      
      {isLoggedIn         
        ? &lt;button className={css[&apos;red&apos;]} onClick={onLogout}&gt;Logout&lt;/button&gt;        
        : &lt;button className={css[&apos;blue&apos;]} onClick={onLogin}&gt;Login&lt;/button&gt;}
    &lt;/div&gt;
  );
}</code></pre><h2 id="hooks-version"><strong>Hooks version</strong></h2><p>Adding the above logic to every component that suffers from rehydration can be very cumbersome.</p><p>Thankfully, there is a way to simplify the code with a straightforward Hook:</p><pre><code class="language-javascript">import { useState, useEffect } from &quot;react&quot;;

const useIsClient = () =&gt; {
  const [isClient, setClient] = useState(false);
  const key = isClient ? &quot;client&quot; : &quot;server&quot;;

  useEffect(() =&gt; {
    setClient(true);
  }, []);

  return { isClient, key };
};

export default useIsClient;</code></pre><p>The usage in our previous component would become:</p><pre><code class="language-javascript">const Component = () =&gt; {
  const { isClient, key } = useIsClient();

  const [token, setToken] = useLocalStorage(&apos;token&apos;, &quot;&quot;);
  const isLoggedIn = token !== &quot;&quot;;

  /* Generate some fake token */
  const onLogin = () =&gt; setToken(Math.random().toString(36).substring(2));
  const onLogout = () =&gt; setToken(&quot;&quot;);

  if ( !isClient ) return null;
  return (
    &lt;div key={key}&gt;
      {isLoggedIn 
        ? &lt;button className={css[&apos;red&apos;]} onClick={onLogout}&gt;Logout&lt;/button&gt;
        : &lt;button className={css[&apos;blue&apos;]} onClick={onLogin}&gt;Login&lt;/button&gt;}
    &lt;/div&gt;
  );
}</code></pre><p>Which looks way cleaner and is ready to be reused across your codebase!</p><h3 id="visualizing-the-issue"><strong>Visualizing the issue</strong></h3><p>The rehydration problem and its workarounds can be easily observed in the following gif:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/Gatsby-hydration-issue-gif.gif" class="kg-image" alt loading="lazy" width="730" height="588" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/Gatsby-hydration-issue-gif.gif 600w, https://www.rafaelquintanilha.com/content/images/2022/11/Gatsby-hydration-issue-gif.gif 730w" sizes="(min-width: 720px) 720px"><figcaption>Rehydration issue visualized</figcaption></figure><p>The first button has the rehydration problem. Notice how it displays the wrong color after we reload the page (i.e., when we ask the server to send the HTML).</p><p>The second button fixes the issue. However, you&#x2019;ll notice it first displays the blue Login button.</p><p>Finally, the last button does not show up until the JavaScript is fully evaluated.</p><p>The last two effects are more noticeable in slow connections. Consider the following simulation of a user within a 3G network:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-hydration-issue-slowdown.gif" class="kg-image" alt loading="lazy" width="730" height="588" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/gatsby-hydration-issue-slowdown.gif 600w, https://www.rafaelquintanilha.com/content/images/2022/11/gatsby-hydration-issue-slowdown.gif 730w" sizes="(min-width: 720px) 720px"><figcaption>Rehydration issue in a slow connection</figcaption></figure><p>The code for the above example is available <a href="https://github.com/rafaelquintanilha/rehydration-issue?ref=rafaelquintanilha.com" rel="noopener noreferrer">in GitHub</a>.</p><p>There&#x2019;s also a <a href="https://gatsby-rehydration-issue.netlify.com/?ref=rafaelquintanilha.com" rel="noopener noreferrer">live version</a> if you want to check it for yourself.</p><h2 id="conclusion"><strong>Conclusion</strong></h2><p>Server-side rendering is a powerful concept and it really makes your application fast.</p><p>Gatsby knows how to best leverage it in order to enhance performance.</p><p>However, you need to be mindful when client and server need to talk. The main takeaways from this piece are:</p><ul><li>Use the <code>key</code> attribute whenever your component changes depending on what it is being rendered</li><li>Prevent the component from rendering until you acknowledge that the application is running in the client to avoid flicker</li><li>Adopt <code>useIsClient</code> in order to reuse the necessary logic for accomplishing the two points above</li></ul>]]></content:encoded></item><item><title><![CDATA[The 5 Best Libs for Accessible React Applications]]></title><description><![CDATA[Accessibility is in high demand and these libraries will save you time.]]></description><link>https://www.rafaelquintanilha.com/the-5-best-libs-for-accessible-react-applications/</link><guid isPermaLink="false">637066ea42a473003d9dcb71</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[Accessibility]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Tue, 08 Oct 2019 03:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Creating accessible applications is hard. There is a wide range of guidelines to follow, plenty of compatibility issues and sometimes the results aren&apos;t easily perceived. Nonetheless, accessible principles really enhance your software and, the most important thing, make sure it is usable across a diverse set of people.</p>
<p>The <a href="https://www.w3.org/WAI/standards-guidelines/wcag/?ref=rafaelquintanilha.com">Web Content Accessibility Guidelines (WCAG)</a> have the standards for developing accessible applications. However, implementing each principle from scratch is extremely time-consuming. Not only you need to make sure your app is behaving well but browsers vary in some implementations and chances are you will end up fixing weird bugs in older browsers. Speaking from experience, it&apos;s frustrating.</p>
<p>Thankfully, React makes UI reusability a smooth experience, which means that if you have a particular widget, say a <a href="https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html?ref=rafaelquintanilha.com">combobox</a>, you can embed accessible behavior once and reuse it later. That prompted a surge in the number of accessible libraries that, if used correctly, can save you <strong>a lot</strong> of time.</p>
<p>The following is a non-exhaustive unordered list of accessible React libraries that I have <em>personally</em> used in my projects. I can attest they work really well in real-world applications that are WCAG compliant, so if that&apos;s a requirement for you, this post will be really helpful.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="1-reach-ui">1. Reach UI</h2>
<p><a href="https://ui.reach.tech/?ref=rafaelquintanilha.com">Reach UI</a> is perhaps the most complete set of accessible components for React. The collection is vast and it was developed with <em>accessibility first</em> as a principle by <a href="https://twitter.com/ryanflorence?ref=rafaelquintanilha.com">Ryan Florence</a>.</p>
<p>This library is definitely a must-see when you are looking for accessible components. Docs are great, customization is easy and you can choose to install only a particular component (e.g. <a href="https://ui.reach.tech/tooltip?ref=rafaelquintanilha.com">Tooltip</a>) instead of the whole lib. This makes the library particularly suited for dropping it in an existent application without increasing its bundle size too much.</p>
<p>When choosing an accessible component, often you are more interested in its <em>behavior</em> rather than the styling. Reach UI components have minimal styling, so you have all you need to style them the way you fancy.</p>
<p>I had a particularly good experience with <a href="https://ui.reach.tech/menu-button?ref=rafaelquintanilha.com"><code>MenuButton</code></a> and can&apos;t recommend it enough for things like dropdowns (I had a lot of headaches using <a href="https://react.semantic-ui.com/modules/dropdown/?ref=rafaelquintanilha.com">Semantic UI Dropdown</a> in the past, so this was a life-changer!)</p>
<p>Make sure you check all elements of the library as it&apos;s almost certain you can benefit from at least one of them.</p>
<h2 id="2-react-modal">2. React Modal</h2>
<p><a href="http://reactcommunity.org/react-modal/?ref=rafaelquintanilha.com">React Modal</a> is probably one of the libraries that I have most used in my React applications. It&apos;s a very common requirement to have a modal overlay, and the folks from <code>react-modal</code> have really nailed it.</p>
<p>If not done properly, modals can really ruin the navigation experience for someone using only a keyboard. Modals should implement <a href="https://www.w3.org/TR/UNDERSTANDING-WCAG20/keyboard-operation-trapping.html?ref=rafaelquintanilha.com">focus trapping</a>, which means that the keyboard should interact within the modal, not with what is <em>underneath</em> it. Long story short, it&apos;s a mess.</p>
<p>That&apos;s why <code>react-modal</code> is really valuable &#x2014; it covers everything you need about focus management and works very well with screenreaders. Their docs are comprehensive and there are a lot of examples online.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="3-react-select">3. React Select</h2>
<p><a href="https://react-select.com/home?ref=rafaelquintanilha.com">React Select</a> is one of the most used React libraries out there and the most powerful combobox I&apos;ve ever used within the React community. There are tons of customizations and you can use them for both simple and complex use cases.</p>
<p>I mentioned earlier that Reach UI has a combobox and that&apos;s true. However, sometimes your combo needs extra functionality. For example, you might want to be able to select multiple options (and therefore need the option to remove them as well). Or maybe you want to dynamically add options (like creating tags). In those situations, <code>react-select</code> might be a safer bet. The docs are amazing, it&apos;s fully customizable and you can handle dynamic requirements with the powerful <a href="https://react-select.com/creatable?ref=rafaelquintanilha.com"><code>Creatable</code></a>.</p>
<p>Notice, however, that <code>react-select</code> is more opinionated, meaning that if you have a really custom design or requirements, you will spend some time making it <a href="https://react-select.com/styles?ref=rafaelquintanilha.com">look exactly how you want</a>. The library takes advantage of <a href="https://emotion.sh/?ref=rafaelquintanilha.com">emotion</a>, so make sure you check it out as well.</p>
<h2 id="4-react-tabs">4. React Tabs</h2>
<p><a href="https://github.com/reactjs/react-tabs?ref=rafaelquintanilha.com">React Tabs</a> is a simple-to-use, fully customizable alternative for creating accessible tabs in React. This is one of my favorite libraries and the best thing about it is that it comes with no styling at all. It will require some upfront work to make it look like you want, but in the end it pays off.</p>
<p>One of the best aspects of tabs is that they are flexible by nature and really help you leverage content you want to display. This example was created using <code>react-tabs</code> and minimal configuration and styling:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/tabs.gif" class="kg-image" alt loading="lazy" width="1211" height="462" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/tabs.gif 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/tabs.gif 1000w, https://www.rafaelquintanilha.com/content/images/2022/11/tabs.gif 1211w" sizes="(min-width: 720px) 720px"><figcaption>React Tabs example</figcaption></figure><!--kg-card-begin: markdown--><p>Again, there is an overlap with <a href="https://ui.reach.tech/tabs/?ref=rafaelquintanilha.com">Reach UI Tabs</a>. They share the same principle and I&apos;ll leave it to you the decision of which is best for your project.</p>
<h2 id="5-react-datepicker">5. React Datepicker</h2>
<p>Datepickers are troublesome components. They can be hard to operate on mobile devices and frequently break users&apos; expectations (are you going to make a 40-year-old user go back 40 years in the calendar to select his or her birthdate?). However, they do work well for relatively close dates (booking a flight or a hotel, for example) and they are somehow expected for users.</p>
<p>Unfortunately, we can&apos;t rely on <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date?ref=rafaelquintanilha.com">input date</a> as its compatibility with older browsers is poor and its implementation varies. How to solve the datepicker issue then?</p>
<p>The simplest yet powerful solution that I found is <a href="https://reactdatepicker.com/?ref=rafaelquintanilha.com"><code>react-datepicker</code></a>. It does pretty much what you expect right off the bat. It has great <a href="https://github.com/Hacker0x01/react-datepicker/?ref=rafaelquintanilha.com#keyboard-support">keyboard support</a> and it&apos;s under active development.</p>
<p>Notice, however, that it doesn&apos;t try to solve all your problems (and sometimes this is a strength). So if all you want is a year picker, perhaps a single dropdown using <code>react-select</code> is best. To be frank, this excess of customization is what makes me favor <code>react-datepicker</code> over <a href="https://github.com/airbnb/react-dates?ref=rafaelquintanilha.com">AirBnB&apos;s <code>react-dates</code></a>. Arguably more famous, I had to spend too much time in <code>react-dates</code> docs when I used it, sometimes with a not so great experience. But if <code>react-datepicker</code> doesn&apos;t cut for you, consider <code>react-dates</code> as an alternative.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>If you have a hard requirement of accessibility (e.g. being WCAG compliant), truth is that you will need to spare some time to get it right. However, if you plan for it ahead and have some experience in the subject, creating accessible applications will become less and less painful.</p>
<p>Consider accessibility as a natural requirement, not a <em>plus</em> for your application (the same way that writing tests isn&apos;t a plus, but an investment). Unfortunately, this might include dropping huge collections of UI components (e.g. <a href="https://react.semantic-ui.com/?ref=rafaelquintanilha.com">Semantic UI</a>), that will hardly be as compliant as you need.</p>
<p>The good news is that with the libraries you have seen in this post you have enough to cover most hard-to-implement-from-scratch use cases out there. Give them a try, bake them naturally into your applications and help to create a more inclusive and satisfactory internet.</p>
<p>Did I forget to mention a relevant library? Feel free to reach me on <a href="https://twitter.com/webquintanilha?ref=rafaelquintanilha.com">Twitter</a> and help me expand this list!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Create a Serverless React Application]]></title><description><![CDATA[Let us understand what serverless really means, what's good about it and how you can take advantage of this architecture when building React apps.]]></description><link>https://www.rafaelquintanilha.com/create-a-serverless-react-application/</link><guid isPermaLink="false">6370603342a473003d9dcb24</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[ButterCMS]]></category><category><![CDATA[Netlify]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 31 Jul 2019 03:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>In the world of software development, sometimes it might be hard to keep up with all the new trends and buzzwords. Developers love new things, so it&#x2019;s understandable that preferences and approaches change over time, although it might happen overwhelmingly quickly.</p>
<p>One of the latest buzzwords to become popular is serverless. Somehow, it seems to be everywhere now, empowering the newest startups as well as the tech giants. But what is serverless after all? Is it worth knowing?</p>
<p>In this article, I will guide you through learning what serverless really is, the reason why it is so powerful and give you some heuristics to help you decide if serverless is well suited for your project. Later, we will build a simple serverless app using <a href="https://www.netlify.com/?ref=rafaelquintanilha.com">Netlify</a> and <a href="https://buttercms.com/?ref=rafaelquintanilha.com">ButterCMS</a> to help you better understand the concepts explained throughout the text.</p>
<p>So what is serverless?</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="the-serverless-architecture">The Serverless Architecture</h2>
<p>The first and maybe unexpected thing you need to know about serverless is that it <em>actually</em> has servers. Although it might sound contradictory, this is relieving once you need to keep your back-end separated from the client. Why do we call it &#x201C;serverless&#x201D; then?</p>
<p>The main difference between <em>serverless</em> and <em>serverful</em> applications is that for serverless applications, the servers management is taken care of for you. That means they still exist and function as designed, but you are free from the maintenance burden. By &#x201C;burden&#x201D; I mean managing availability, scalability, redundancy, uptime, orchestration, and all many other things that are important to modern web applications.</p>
<p>Before digging deeper into our definition, let us first understand why serverless emerged in the first place.</p>
<h3 id="the-motivation-behind-serverless">The motivation behind serverless</h3>
<p>Not long ago, applications ran locally in private-owned data centers. This changed when cloud computing became popular, smashing costs and enabling developers and companies to move their infrastructure to the web and focus on their products instead. Companies such as Amazon specialized in developing reliable and distributed data centers that could be accessed anywhere in the world at the same time.</p>
<p>Although this was a turning point for software development, it also brought a new set of problems to be solved &#x2060;&#x2014; make sure the server is available at any time, scale up its capacity based on a surge in demand (and conversely scale down during peaceful times), dynamically allocate memory to the most sensitive processes, and so on.</p>
<p>What in the beginning was supposed to be an infrastructure relief ended up becoming a headache once more. Therefore, the demand for headache-free software development was still around (and will likely stay around for as long as software developers live). How do you keep the improvements brought by cloud computing <em>without</em> spending too much time managing the cloud?</p>
<p>The answer is, of course, serverless.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="what-is-serverless">What is serverless?</h3>
<p>I mentioned that serverless architecture, in fact, uses servers, but that they are concealed from you. This is still a loose definition, so it&#x2019;s time to go deeper into this.</p>
<p>The truth is that the definition of serverless varies a lot, some very technical, which can be confusing to newcomers. I&#x2019;ll start by defining serverless as <em>architecture</em> or <em>methodology</em>. Finally, simply put, <strong>serverless architecture is when you perform computations without having to think about machine resource allocation</strong>. That is, the perks of cloud computing are seamlessly integrated into your workflow.</p>
<p>A more technical definition would be the following:</p>
<blockquote>
<p>Serverless is an event-driven, ephemeral and stateless cloud-based architecture that dynamically allocates machine resources.</p>
</blockquote>
<h3 id="lambda-functions">Lambda functions</h3>
<p>It all sounds too good to be true, but what is underneath a serverless architecture? The key is what we call a <em>lambda function</em>.</p>
<p>A <em>lambda function</em> is simply an anonymous function. Consider this JavaScript example:</p>
<pre><code class="language-js">const multiplyBy = x =&gt; {
  return y =&gt; x * y
}

const triple = multiplyBy(3)

triple(10) // returns 30
</code></pre>
<p>Notice that the original function, <code>multiplyBy</code>, returns an (anonymous) function. This function has the original value passed to <code>mutiplyBy</code> in its scope, what we call closure.</p>
<p>In a serverless application, Lambda functions are invoked, perform the desired operation, and vanish (that&#x2019;s why serverless is <em>ephemeral</em>). This process is handled by the serverless provider, the most famous being <a href="https://aws.amazon.com/lambda/?ref=rafaelquintanilha.com">AWS Lambda</a>. In the end, all you need to do is to write your function and let the provider call it when it&#x2019;s time (hence, <em>event-based</em>) while doing all machine allocation. Because you don&#x2019;t control the environment where your code is running, you need to assume a <em>stateless</em> function, i.e., there is no data persistence in between calls.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/lambda-function.png" class="kg-image" alt loading="lazy" width="2000" height="1029" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/lambda-function.png 600w, https://www.rafaelquintanilha.com/content/images/size/w1000/2022/11/lambda-function.png 1000w, https://www.rafaelquintanilha.com/content/images/size/w1600/2022/11/lambda-function.png 1600w, https://www.rafaelquintanilha.com/content/images/2022/11/lambda-function.png 2100w" sizes="(min-width: 720px) 720px"><figcaption>Lambda function diagram</figcaption></figure><!--kg-card-begin: markdown--><p>So far we have finally learned <em>what</em> serverless is, conceptually and technically. Next, we will see <em>why</em> it is important.</p>
<h2 id="why-serverless-a-look-at-what-problems-it-solves">Why Serverless? A look at what problems it solves</h2>
<p>When developing an application, your prime goal is to focus on the problem you are trying to solve. Ultimately, it means that all work you need to do that is not directly linked to your goal needs to be minimized or, better, eliminated.</p>
<p>If there is a surge in the usage of your app, ideally it shouldn&#x2019;t make any difference to your users. In reality, though, they might expect slowness, a drop in responsiveness and even no service at all if your server crashes. In order to prevent scenarios like this, you need to invest in good infrastructure. Unfortunately, maintaining such a robust infrastructure is time-consuming and expensive.</p>
<p>How can serverless help you with this dilemma?</p>
<h3 id="scales-out-of-the-box">Scales out-of-the-box</h3>
<p>Going serverless means that you are offsetting the responsibility of keeping your application stable regardless of the number of users to the service provider. This peace of mind can be hugely beneficial, not only because of the less amount of work but also because of the certainty that your app is going to behave well even in tail scenarios.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="active-upon-actual-usage">Active upon actual usage</h3>
<p>When you assume the responsibility of maintaining a server, you pay for the (virtual) machine you use. That gives you the freedom to control the server and use it however you see fit. Nonetheless, it comes for a price: you pay for that machine even if you are not using. So if your application is only accessed in specific periods of time, you might end up wasting money. Suppose that you have a certificate service that issues certificates to students upon the completion of a course. If the course is still ongoing, there&#x2019;s no reason to keep the server up, yet you will need to. But in a serverless approach, every request will call a function that will directly impact your bill. This way, when there are no requests there is also no need to pay.</p>
<h3 id="cloud-lock-ins-vs-employee-lock-ins">Cloud lock-ins vs employee lock-ins</h3>
<p>If you want top-quality infrastructure management, you will need to assemble a DevOps team. That by itself will start to get expensive, but that&#x2019;s not the worst of it. The main problem is that <em>changing personnel is way more difficult than changing a cloud provider</em>. So if you decide to switch technologies or are not satisfied with the current status of your company&#x2019;s infrastructure, you will likely have a hard time. However, by adopting a serverless strategy, if you ever need to change providers you can expect a less painful experience.</p>
<h3 id="developer-experience">Developer experience</h3>
<p>It goes without saying that developers&#x2026; well, like to develop. If you take from them the responsibility to overlook the infrastructure, they will get more productive by keeping their eyes on the end goal, i.e., creating an awesome app. A stressful working environment can kill devs productivity and actual care for their well being will bring you collateral improvements.</p>
<p>Now that we have seen some of the benefits of a serverless approach, let us check when it might make sense to you.</p>
<h2 id="when-to-use-a-serverless-architecture">When to use a Serverless Architecture?</h2>
<p>Granted, serverless brings a lot of joy back to development and can be a pretty useful resource. However, if you want to adopt this methodology, it&#x2019;s indispensable that you know why and if it does help you, and avoid just following the hype.</p>
<p>So, what are some indicators that serverless is a good choice for you?</p>
<h3 id="little-control-over-your-server">Little control over your server</h3>
<p>Serverless diminishes your maintenance overhead because you do not own a server anymore. That also means that you can&#x2019;t do whatever you want, like installing different tools and languages. So if your service provider allows for NodeJS functions, you can&#x2019;t simply install Python on it and write Django code. Always consider how much control you need.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="short-computations">Short computations</h3>
<p>Lambda functions are event-driven, which means that they are called when something happens (for example, when a user is created). Serverless providers will set a maximum time limit your function can run to avoid that a single call drains all machine&#x2019;s memory. This limit will vary from provider to provider, but it is important that you realize that if your application performs long and expensive computations, going serverless may be a problem for you.</p>
<h3 id="small-throughput">Small throughput</h3>
<p>We have seen that one advantage of serverless is that you are billed per function request and not by uptime (like traditional hosts such as <a href="https://www.digitalocean.com/?ref=rafaelquintanilha.com">DigitalOcean</a>). This was interesting in our previous certificate example, but may not be well suited for applications with high throughput, that is, with too many requests per second. Real-time applications that poll the server too much can rapidly increase the cost of your project. Note that it doesn&#x2019;t necessarily mean that serverless is a bad idea, once all other advantages (even intangible ones, such as developer experience) might be worth the extra cost.</p>
<h3 id="no-data-persistence">No data persistence</h3>
<p>Because you don&#x2019;t own the machine, you can&#x2019;t assume you have access to any files in there either. That means that your Lambda function should be stateless. If your application doesn&#x2019;t need to persist any state (e.g. save data), serverless becomes really powerful. However, that isn&#x2019;t the case in most situations. But even when you need to persist data, there is still a silver lining &#x2013; services like <a href="https://aws.amazon.com/dynamodb/?ref=rafaelquintanilha.com">Amazon DynamoDB</a> and <a href="https://www.mongodb.com/cloud/atlas?ref=rafaelquintanilha.com">MongoDB Atlas</a> allow you to save and retrieve data through an API.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="prototyping">Prototyping</h3>
<p>I avoided mentioning prototyping earlier because I wanted to emphasize that serverless is <em>production-ready</em>. Top companies are heavily investing in it and there is no reason you should avoid it because of production concerns. That being said, serverless is tremendously helpful when prototyping. Once a prototype or early-stage application has no need to bother with auto scale, high throughput, and other infrastructure particularities, going serverless can definitely help you with your MVP.</p>
<p>The topics above are good heuristics for you to ask when considering a serverless architecture. But aside from that, there are also plenty of common use-cases that benefit from being serverless:</p>
<ul>
<li>Creating an API to handle subscribing to a newsletter (e.g. integrating with <a href="https://mailchimp.com/?ref=rafaelquintanilha.com">Mailchimp</a>);</li>
<li>Handling authorization (e.g. using <a href="https://www.netlify.com/docs/identity/?ref=rafaelquintanilha.com">Netlify&#x2019;s Identity</a>);</li>
<li>Sending emails (e.g. using <a href="https://sendgrid.com/?ref=rafaelquintanilha.com">SendGrid</a>);</li>
<li>Building an API gateway to send SMS (e.g. using <a href="https://www.twilio.com/blog/a-how-to-send-text-messages-from-your-static-site-using-netlify-twilio-and-serverless-functions?ref=rafaelquintanilha.com">Twilio</a>);</li>
<li>And even [playing Pokemon](<a href="https://pokeless-eu.rauchg.now.sh/?ref=rafaelquintanilha.com">https://pokeless-eu.rauchg.now.sh/</a>! (Well, maybe not very common)</li>
</ul>
<p>I encourage you to check the <a href="https://functions.netlify.com/examples/?ref=rafaelquintanilha.com">Netlify&#x2019;s Function Examples</a> to get some inspiration of what you can achieve by adopting a serverless architecture.</p>
<p>We have covered serverless in great depth, by defining what it is, understanding why it can be useful and finally learning which situations can benefit the most from this methodology. Next, we will put the theory aside and learn how to create a serverless API in practice.</p>
<h2 id="serverless-in-practice-with-buttercms-and-netlify">Serverless in practice with ButterCMS and Netlify</h2>
<p>For the rest of this article, we will build a serverless API using Netlify which will fetch blog posts stored in <a href="https://buttercms.com/?ref=rafaelquintanilha.com">ButterCMS</a>, the headless Content Management System, and group them by month. This is a simple feature but aims to show how you can leverage both Butter and serverless by doing computations in the back-end (and therefore increase the performance of your app). Notice that our application is stateless, once it doesn&#x2019;t need to persist any data (it will always read from Butter&#x2019;s API). Finally, we will build a simple front-end to exemplify how you could fetch this data in a real application.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="setting-up-the-project">Setting up the project</h3>
<p>Before we start, all code is in <a href="https://github.com/rafaelquintanilha/butter-serverless-example?ref=rafaelquintanilha.com">this GitHub repo</a> and a simple demo can be accessed here.</p>
<p>Let&#x2019;s start by creating a new repo using <a href="https://github.com/facebook/create-react-app?ref=rafaelquintanilha.com">create-react-app</a>. If your npm version is 5.2 or higher, npx will be available to you. Otherwise, you can install create-react-app by running <code>npm install -g create-react-app</code>.</p>
<pre><code class="language-sh">npx create-react-app butter-serverless-example
cd butter-serverless-example
</code></pre>
<p>We will use the power of <a href="https://www.netlify.com/products/dev/?ref=rafaelquintanilha.com">Netlify Dev</a> in this tutorial. Netlify Dev allows you to replicate Netlify&#x2019;s environment in your machine. It means that you can develop locally as you are in production, inject env variables, share live URLs and much more. Let us explore what it can do for us.</p>
<p>If you haven&#x2019;t already, install the Netlify CLI:</p>
<pre><code class="language-sh">npm install netlify-cli -g
</code></pre>
<p>Then make sure that you are logged in:</p>
<pre><code class="language-sh">netlify login
</code></pre>
<p>Once you are logged in, the next step is to link your folder to a Netlify project. Make sure you have your project created in Netlify. You can easily do that from the UI or use:</p>
<pre><code class="language-sh">netlify deploy
</code></pre>
<p>Whatever way you choose, it is pretty straightforward to get it done (I personally like to create a repo in GitHub and then create a new site in Netlify directly from Git). After this, run the following command to link your app:</p>
<pre><code class="language-sh">netlify link
</code></pre>
<p>If you have started your project from Git, the CLI will automatically recognize the address. If that&#x2019;s not the case, you can provide your site&#x2019;s name or ID in order to finish the process. Both information can be found on your project&#x2019;s settings page.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="creating-your-first-function">Creating your first function</h3>
<p>Once the setup is done we can start by creating our first function. Functions need to live in a folder inside your app, so go ahead and create <code>src/functions</code> in your project.</p>
<p>Next, at the root of <code>butter-serverless-example</code> create Netlify&#x2019;s configuration file <code>netlify.toml</code> and add the following:</p>
<pre><code>[build]
  functions = &quot;src/functions&quot;
</code></pre>
<p>Which basically points Netlify to the right folder.</p>
<p>Let us use the CLI to create our first function:</p>
<pre><code class="language-sh">netlify functions:create
</code></pre>
<p>Many examples will display. They give you an overview of the many possibilities you have with serverless functions. For this example, select the <code>hello-world</code> option and name it <code>posts-by-month</code>. After that, go check the functions folder and notice that <code>posts-by-month/posts-by-month.js</code> is there.</p>
<p>In order to test that everything is working as expected, run <code>netlify dev</code> and go to <a href="http://localhost:8888/?ref=rafaelquintanilha.com">http://localhost:8888</a>. The CRA default app will be there. But how do we test that our function is working?</p>
<p>Every function in Netlify is mapped to a specific URL <code>/.netlify/functions/&lt;function name&gt;</code>. Simply go to <a href="http://localhost:8888/.netlify/functions/posts-by-month?ref=rafaelquintanilha.com">http://localhost:8888/.netlify/functions/posts-by-month</a> and check that everything works.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="fetching-from-butter">Fetching from Butter</h3>
<p>Our <code>posts-by-month.js</code> function currently only returns some dummy data. But before we fix that, let us examine closely what is going on:</p>
<pre><code class="language-jsx">exports.handler = async (event, context) =&gt; {
  try {
    const subject = event.queryStringParameters.name || &apos;World&apos;
    return {
      statusCode: 200,
      body: JSON.stringify({ message: `Hello ${subject}` }),
    }
  } catch (err) {
    return { statusCode: 500, body: err.toString() }
  }
}
</code></pre>
<p>Every function needs to export a handler, which in this case is an async function (convenient once we will need to asynchronously fetch data from Butter&#x2019;s API). This function needs to return an object containing a <code>statusCode</code> indicating the HTTP Status of the request and a body with the payload. You can learn more about the <code>handler</code> method in the <a href="https://www.netlify.com/docs/functions/?ref=rafaelquintanilha.com#the-handler-method">docs</a>.</p>
<p>The process of fetching data from Butter is pretty straightforward. Make sure you have it installed:</p>
<pre><code class="language-sh">npm install --save buttercms
</code></pre>
<p>And then setup Butter&#x2019;s client pretty much how you would do with a regular React app:</p>
<pre><code class="language-jsx">const Butter = require(&apos;buttercms&apos;);
const API_KEY = &#x201C;&lt;YOUR_API_KEY&gt;&#x201D;;
const butter = Butter(API_KEY);

exports.handler = async (event, context) =&gt; {
  try {
    const response = await butter.post.list({page: 1, page_size: 10});
    return {
      statusCode: 200,
      body: JSON.stringify({ data: response.data })
    };
  } catch (err) {
    return { statusCode: 500, body: err.toString() };
  }
};
</code></pre>
<p>Don&#x2019;t forget to change <code>&lt;YOUR_API_KEY&gt;</code> to your personal key. Go again to <a href="http://localhost:8888/.netlify/functions/posts-by-month?ref=rafaelquintanilha.com">http://localhost:8888/.netlify/functions/posts-by-month</a> and verify that it&#x2019;s returning the correct data.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="grouping-by-month">Grouping by month</h3>
<p>The API is returning data, but that&#x2019;s not exactly what we want. Ideally, we need to leverage the server processing power to make some computations for us. Let us grab only the published attribute of each post and map it to its corresponding month. The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date?ref=rafaelquintanilha.com">JavaScript Date object</a> allows us to do that by creating a <code>Date</code> instance and calling the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth?ref=rafaelquintanilha.com">getMonth</a> method. This method returns a number ranging from 0-11 which represents the months from January to December.</p>
<p>Our function should look like this:</p>
<pre><code class="language-jsx">...
const response = await butter.post.list({page: 1, page_size: 10});
const postsByMonth = {};
response.data.data
  .map(post =&gt; new Date(post.published).getMonth())
  .forEach(monthIndex =&gt; {
    if ( postsByMonth[monthIndex] ) postsByMonth[monthIndex]++;
    else postsByMonth[monthIndex] = 1;
  });
return {
  statusCode: 200,
  body: JSON.stringify(postsByMonth)
};
</code></pre>
<p>Basically, we create a <code>postsByMonth</code> object which will hold the total number of posts retrieved by the API for every month that has any record. So if we had 2 posts in April, <code>postsByMonth[3]</code> will return <code>2</code>. If none were written in March, <code>postsByMonth[2]</code> will be <code>undefined</code>.</p>
<p>Our API is already achieving our simple requirements, but let&#x2019;s improve it a bit.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="limiting-the-number-of-returned-posts">Limiting the number of returned posts</h3>
<p>In the hello world example we paid little attention to this line:</p>
<pre><code class="language-jsx">const subject = event.queryStringParameters.name || &apos;World&apos;
</code></pre>
<p>We can resort to a similar technique to allow the user to set the limit for the query.</p>
<pre><code class="language-jsx">...
exports.handler = async (event, context) =&gt; {
  try {
    const limit = event.queryStringParameters.limit || 10;
    const response = await butter.post.list({page: 1, page_size: limit});
    ...
  };
</code></pre>
<p>That&#x2019;s not the only way to pass data to our Lambda function. The body of the request can be accessed via:</p>
<pre><code class="language-js">const body = JSON.parse(event.body)
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="adding-an-environment-variable">Adding an environment variable</h3>
<p>Currently, we are hardcoding the API key in the code. This is less problematic than having it in the client, but it&#x2019;s still suboptimal (you might forget and commit its value to Git, for example). One of the nicest features of Netlify Dev is that it automatically injects all env variables that you have set on Netlify in your local server.</p>
<p>Open your site&#x2019;s dashboard on Netlify and head to <em>Settings &gt; Build &amp; Deploy &gt; Environment</em>. There, click on <em>Edit Variables</em> and add <code>BUTTER_API_KEY</code> as &#x201C;Key&#x201D; and your API key as &#x201C;Value&#x201D;.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/netlify-env-panel.png" class="kg-image" alt loading="lazy" width="974" height="331" srcset="https://www.rafaelquintanilha.com/content/images/size/w600/2022/11/netlify-env-panel.png 600w, https://www.rafaelquintanilha.com/content/images/2022/11/netlify-env-panel.png 974w" sizes="(min-width: 720px) 720px"><figcaption>Netlify environment panel</figcaption></figure><!--kg-card-begin: markdown--><p>Next, initialize Butter making sure you read the API key from the env context:</p>
<pre><code class="language-jsx">const Butter = require(&apos;buttercms&apos;);
const API_KEY = process.env.BUTTER_API_KEY;
...
</code></pre>
<p>Restart the dev server and check that it works!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="calling-the-api">Calling the API</h3>
<p>So far we have been testing our API directly in the browser. In order to exemplify how to consume this data in a real application, let us write a simple front-end that will make the request.</p>
<p>Delete everything in <code>src/App.js</code> and replace with:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;

function App() {
  return (
    &lt;div&gt;
      &lt;button&gt;Fetch API&lt;/button&gt;
    &lt;/div&gt;
  )
}

export default App
</code></pre>
<p>Next, install <a href="https://www.npmjs.com/package/isomorphic-fetch?ref=rafaelquintanilha.com">isomorphic-fetch</a>:</p>
<pre><code class="language-sh">npm install --save isomorphic-fetch
</code></pre>
<p>We want to fetch data upon click and then render a table with the count for every month. If a month is not present, it means there were no posts. The full code is as follows:</p>
<pre><code class="language-jsx">import React, { useState } from &apos;react&apos;
import fetch from &apos;isomorphic-fetch&apos;

const indexToMonth = index =&gt; {
  switch (index) {
    case 0:
      return &apos;Jan&apos;

    // Omitted for brevity

    case 11:
      return &apos;Dec&apos;
    default:
      return &apos;&apos;
  }
}

function App() {
  const [postsByMonth, setPostsByMonth] = useState(null)

  const onClick = async () =&gt; {
    try {
      const response = await fetch(&apos;/.netlify/functions/posts-by-month&apos;)
      const json = await response.json()
      setPostsByMonth(json)
    } catch (e) {
      console.error(e)
    }
  }

  return (
    &lt;div&gt;
      &lt;button onClick={onClick}&gt;Fetch API&lt;/button&gt;
      {postsByMonth &amp;&amp; (
        &lt;table&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Month&lt;/th&gt;
              &lt;th&gt;Posts&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            {Array(12)
              .fill(0)
              .map((el, i) =&gt; (
                &lt;tr key={i}&gt;
                  &lt;td&gt;{indexToMonth(i)}&lt;/td&gt;
                  &lt;td&gt;{postsByMonth[i] || 0}&lt;/td&gt;
                &lt;/tr&gt;
              ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      )}
    &lt;/div&gt;
  )
}

export default App
</code></pre>
<p>All we do is to fetch data from our serverless API and save it with <code>useState</code>. If you are unfamiliar with React Hooks, check this <a href="https://www.rafaelquintanilha.com/how-to-reuse-logic-with-react-hooks">comprehensive article</a> which will guide you through what is essential.</p>
<p>Then, we iterate over an array of size 12 (using ES6 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill?ref=rafaelquintanilha.com">Array.fill</a> method) and render the correct value for each month. For brevity, I omitted the full extent of <code>indexToMonth</code>, but it should be pretty clear.</p>
<p>Go to <a href="http://localhost:8888/?ref=rafaelquintanilha.com">http://localhost:8888/</a> and check your serverless-powered app!</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/fetch.gif" class="kg-image" alt loading="lazy" width="265" height="333"><figcaption>Fetching data from serverless API</figcaption></figure><!--kg-card-begin: markdown--><h2 id="final-thoughts">Final thoughts</h2>
<p>Serverless goes way beyond the current hype. It definitely removes development overhead and therefore has inherent value. In the book <em>Antifragile</em>, the author Nassim Nicholas Taleb warns us against &#x201C;overhyping&#x201D; and &#x201C;neomania&#x201D;. According to him:</p>
<blockquote>
<p>&#x201C;People acquire a new item, feel more satisfied after an initial boost, then rapidly revert to their baseline of well-being. So when you &#x201C;upgrade&#x201D;, you feel a boost of satisfaction with changes in technology. But then you get used to it and start hunting for the new new thing.&#x201D;</p>
</blockquote>
<p>We can apply the same principle to software development. Yet, things <em>do</em> evolve and <em>do</em> get better. How can you tell what&#x2019;s worthy from what&#x2019;s purely <em>neomania</em>?</p>
<p>Taleb exemplifies with wall-to-wall windows. With today&#x2019;s technology, we can avoid heavy and thick windows that helped our predecessors&#x2019; homes stay warm. That approaches humans to nature. In other words, when technology is used to <em>remove</em> a constraint imposed by <em>technology itself</em> in the past.</p>
<p>How can we relate that principle with what we learned today? Serverless connects us with what is really important (developing a great product) by removing the infrastructure burden that was important in the past but can be dispensable in some cases.</p>
<p>Anyway, we have seen that serverless is not a silver bullet. In particular, it might not suit your needs if you need more control over your server.</p>
<p>Finally, combine Netlify with ButterCMS to avoid expensive computations in your clients&#x2019; browsers, improve security and enhance the API to fit your requirements.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Testing Library Common Scenarios]]></title><description><![CDATA[How to write tests that are common to many applications using React Testing Library.]]></description><link>https://www.rafaelquintanilha.com/react-testing-library-common-scenarios/</link><guid isPermaLink="false">637058a042a473003d9dcaf3</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[React Testing Library]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Tue, 16 Jul 2019 03:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>tl;dr &#x2013; <a href="http://react-testing-library-examples.netlify.com/?ref=rafaelquintanilha.com">React Testing Library Examples</a></strong></p>
<p>When I was first introduced to <a href="https://testing-library.com/react?ref=rafaelquintanilha.com">React Testing Library</a>, my first reaction was &quot;alright, yet another React framework&quot; and I didn&apos;t pay much attention to it. The library quickly gained traction, but as I had been working with Enzyme for a while, I didn&apos;t bother.</p>
<p>With the introduction of React Hooks, testing with Enzyme became harder. To be frank, I never completely enjoyed Enzyme and paradoxically this was the main reason I relucted to switch libraries &#x2013; I was too committed. Moreover, most of the test scenarios I use in my workdays were already developed and I needed to do little thinking when creating new tests.</p>
<p>Yet, every now and then I&apos;d struggle writing some test, especially if it involved mocking API calls. Somehow the tests didn&apos;t feel right. Finally, I decided to give React Testing Library a shot and, well, as you might have imagined, I love it!</p>
<p><strong>This article is a compilation of common test scenarios that you are likely to find when developing your application</strong>. For each scenario, I describe the problem and how you can write a test for it with <a href="https://jestjs.io/?ref=rafaelquintanilha.com">Jest</a> + React Testing Library.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="table-of-contents">Table of Contents</h4>
<ol>
<li><a href="#scenario-1---controlled-component">Controlled Component</a></li>
<li><a href="#scenario-2---input-change">Input Change</a></li>
<li><a href="#scenario-3---focused-element">Focused Element</a></li>
<li><a href="#scenario-4---effects">Effects</a></li>
<li><a href="#scenario-5---settimeout">setTimeout</a></li>
<li><a href="#scenario-6---fetch">Fetch</a></li>
<li><a href="#scenario-7---multiple-api-calls">Multiple API calls</a></li>
</ol>
<p>If you are reading this post as a reference, you can skip the next session. Else, let us understand what makes RTL <em>better</em>.</p>
<h3 id="why-react-testing-library">Why React Testing Library</h3>
<blockquote>
<p>The more your tests resemble the way your software is used, the more confidence they can give you.</p>
</blockquote>
<p>The above sentence is the <a href="https://testing-library.com/docs/guiding-principles?ref=rafaelquintanilha.com">guiding principle</a> of React Testing Library and in fact says a lot about it. With Enzyme, tests were always uncomfortably implementation-dependent. They were fragile to changes.</p>
<p>With RTL, when you render a component, you have the actual DOM element exposed to you. This makes your test way more predictable and reduces the learning curve (it boils down to good ol&apos; JavaScript).</p>
<p>One can argue that all you can do with RTL is possible to be done with Enzyme. True. But in the end, RTL was designed to <em>enforce good practices</em>. That&apos;s why you <code>render</code> and access elements through accessibility-compliant attributes (get via semantic attributes such as text, label and placeholder, instead of using meaningless class selectors).</p>
<p>Another pleasant difference is that tests are smaller, <a href="https://www.rafaelquintanilha.com/how-to-become-a-bad-developer/#take-pleasure-in-writing-more-code">which is a good thing</a>.</p>
<p>Enough with the prelude, let us take a look at our first scenario.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-1controlled-component">Scenario 1 - Controlled Component</h2>
<p>Suppose that you need to create a button component that is meant to be shared across your app:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;

const Button = props =&gt; {
  return &lt;button onClick={props.onClick}&gt;{props.text}&lt;/button&gt;
}

export default Button
</code></pre>
<p>There are two things that you might want to assert:</p>
<ol>
<li>The button is rendered with the correct text;</li>
<li>Whatever function passed as the <code>onClick</code> prop is called after click.</li>
</ol>
<p>Here&apos;s how you can write a test to address the first point:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import Button from &apos;./Button&apos;
import { render, cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

const defaultProps = {
  onClick: jest.fn(),
  text: &apos;Submit&apos;,
}

test(&apos;button renders with correct text&apos;, () =&gt; {
  const { queryByText } = render(&lt;Button {...defaultProps} /&gt;)
  expect(queryByText(&apos;Submit&apos;)).toBeTruthy()
})
</code></pre>
<p>Notice that <code>render</code> returns functions that allow you to select and manipulate DOM elements. In our case, we are using <a href="https://testing-library.com/docs/dom-testing-library/api-queries?ref=rafaelquintanilha.com#queryby">queryByText</a>, which (surprise!) allows you to query nodes by their text. It will return <code>null</code> if no nodes satisfy the query and throw an error if more than one is found (when you might consider using <a href="https://testing-library.com/docs/dom-testing-library/api-queries?ref=rafaelquintanilha.com#queryallby">queryAllBy</a>).</p>
<p>So our test was able to assert that there is a DOM node whose text is <em>Submit</em>. And if we want to make sure that it works for other prop values too?</p>
<pre><code class="language-jsx">test(&apos;button renders with correct text&apos;, () =&gt; {
  const { queryByText, rerender } = render(&lt;Button {...defaultProps} /&gt;)
  expect(queryByText(&apos;Submit&apos;)).toBeTruthy()

  // Change props
  rerender(&lt;Button {...defaultProps} text=&quot;Go&quot; /&gt;)
  expect(queryByText(&apos;Go&apos;)).toBeTruthy()
})
</code></pre>
<p>The <code>rerender</code> function allows you to manually trigger a rerender, this time with a different prop. Our first test is done!</p>
<p>Now let&apos;s check how we can guarantee that by clicking on the button we call the <code>onClick</code> prop:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;;
import Button from &apos;./Button&apos;;
import { render, fireEvent, cleanup } from &apos;@testing-library/react&apos;;

...

test(&apos;calls correct function on click&apos;, () =&gt; {
  const onClick = jest.fn();
  const { getByText } = render(
    &lt;Button {...defaultProps} onClick={onClick} /&gt;
  );
  fireEvent.click(getByText(defaultProps.text));
  expect(onClick).toHaveBeenCalled();
});
</code></pre>
<p>Here we are creating a simple <a href="https://jestjs.io/docs/en/mock-functions?ref=rafaelquintanilha.com">Jest mock function</a> and passing it as the <code>onClick</code> prop to the <code>Button</code> component. We then use <a href="https://testing-library.com/docs/dom-testing-library/api-queries?ref=rafaelquintanilha.com#getby">getByText</a> to select the button this time (<code>getByText</code> will throw an error if 0 or more than one element matches the query).</p>
<p>With the node selected, we then call <code>fireEvent.click</code>, which is the declarative way of RTL firing events. All we need to do next is to confirm that our mock function was indeed called.</p>
<p>And our first basic scenario is complete. <a href="https://github.com/rafaelquintanilha/react-testing-library-examples/blob/master/src/Button.test.js?ref=rafaelquintanilha.com">The complete test is in GitHub.</a></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-2input-change">Scenario 2 - Input Change</h2>
<p>Another very common use case is an input change that modifies the UI. Consider a text field for the user&apos;s name and a greeting that changes with the input:</p>
<pre><code class="language-jsx">import React, { useState } from &apos;react&apos;

function ChangeInput() {
  const [name, setName] = useState(&apos;&apos;)
  return (
    &lt;div&gt;
      &lt;span data-testid=&quot;change-input-greeting&quot;&gt;
        Welcome, {name === &apos;&apos; ? &apos;Anonymous User&apos; : name}!
      &lt;/span&gt;
      &lt;br /&gt;
      &lt;input
        type=&quot;text&quot;
        aria-label=&quot;user-name&quot;
        placeholder=&quot;Your name&quot;
        value={name}
        onChange={e =&gt; setName(e.target.value)}
      /&gt;
    &lt;/div&gt;
  )
}

export default ChangeInput
</code></pre>
<p>Notice that we are using React Hooks to manage the state. However, <strong>internal implementations shouldn&apos;t matter at all</strong>. Here&apos;s how the test would look like:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import ChangeInput from &apos;./ChangeInput&apos;
import { render, fireEvent, cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

test(&apos;displays the correct greeting&apos;, () =&gt; {
  const { getByLabelText, getByTestId } = render(&lt;ChangeInput /&gt;)
  const input = getByLabelText(&apos;user-name&apos;)
  const greeting = getByTestId(&apos;change-input-greeting&apos;)
  expect(input.value).toBe(&apos;&apos;)
  expect(greeting.textContent).toBe(&apos;Welcome, Anonymous User!&apos;)
  fireEvent.change(input, { target: { value: &apos;Rafael&apos; } })
  expect(input.value).toBe(&apos;Rafael&apos;)
  expect(greeting.textContent).toBe(&apos;Welcome, Rafael!&apos;)
})
</code></pre>
<p>Pretty straightforward, we select the input via the <code>aria-label</code> attribute (a good example of the library enforcing accessibility good practices) and also check that both the greeting and the input have the correct initial value. Then, we call <code>fireEvent.change</code> to trigger a change event, making sure we pass the correct event object with the new input.</p>
<p>Finally, we need to assert that the input has the correct value and the right greeting is being displayed. And there are two of my favorite things with RTL stands:</p>
<ol>
<li>We access values and attributes as we would with regular DOM nodes. So getting an element&apos;s text is as easy as accessing <code>textContent</code>.</li>
<li>Nodes are passed as <em>reference</em>, so if you assign them to a variable <em>before</em> a change, you can use the same variable to later check if any of its attributes have changed. This is a huge plus over Enzyme, where I found myself many times dealing with bugs where I assumed a change would be there but I needed to select the element again. Notice how the same <code>greeting</code> variable has different <code>textContent</code> values based on the event triggered.</li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-3focused-element">Scenario 3 - Focused Element</h2>
<p>Accessible applications need to keep track of the focused element. For example, suppose you want to make sure that after clicking on a button, the focus goes to a given input.</p>
<pre><code class="language-jsx">import React, { useRef } from &apos;react&apos;

const FocusInput = () =&gt; {
  const inputRef = useRef(null)
  return (
    &lt;div&gt;
      &lt;input
        type=&quot;text&quot;
        aria-label=&quot;focus-input&quot;
        ref={inputRef}
        placeholder=&quot;Focus me!&quot;
      /&gt;
      &lt;button onClick={() =&gt; inputRef.current.focus()}&gt;Click to Focus&lt;/button&gt;
    &lt;/div&gt;
  )
}

export default FocusInput
</code></pre>
<p>The <code>useRef</code> hook stores the input&apos;s reference. You can find more about refs in <a href="https://www.rafaelquintanilha.com/the-complete-guide-to-react-refs/">The Complete Guide to React Refs</a>.</p>
<p>Let&apos;s write a test to assert that the input receives focus after click:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import FocusInput from &apos;./FocusInput&apos;
import { render, fireEvent, cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

test(&apos;clicking on button trigger focus on input&apos;, () =&gt; {
  const { getByPlaceholderText, getByText } = render(&lt;FocusInput /&gt;)
  fireEvent.click(getByText(&apos;Click to Focus&apos;))
  const input = getByPlaceholderText(&apos;Focus me!&apos;)
  expect(input).toBe(document.activeElement)
})
</code></pre>
<p>This time we introduce <code>getByPlaceholderText</code>, which can be handy in some situations (however, <a href="https://www.nngroup.com/articles/form-design-placeholders/?ref=rafaelquintanilha.com">a placeholder is not a substitute for a label</a>.</p>
<p>The experience of testing focused elements is, in my opinion, very superior to Enzyme&apos;s. In particular, I love how idiomatic <code>expect(input).toBe(document.activeElement)</code> is.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="snapshots">Snapshots</h4>
<p>Let me introduce how you can do snapshot testing with React Testing Library:</p>
<pre><code class="language-jsx">...

test(&apos;FocusInput matches snapshot&apos;, () =&gt; {
  const { container } = render(&lt;FocusInput /&gt;)
  expect(container.firstChild).toMatchSnapshot();
});
</code></pre>
<p>Notice that <code>render</code> returns a <code>container</code> element. By default, every component is rendered into a <code>div</code>. That&apos;s why we access the element via <code>container.firstChild</code>. There are some occasions when you don&apos;t want to render into a <code>div</code>, e.g. when your component renders a <code>tr</code> and therefore the container needs to be a <code>table</code> element. You can check the <a href="https://testing-library.com/docs/react-testing-library/api?ref=rafaelquintanilha.com#render-options">render API</a> for more information.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-4effects">Scenario 4 - Effects</h2>
<p>We have already covered <code>useState</code> and <code>useRef</code>. Next, let us combine them with <code>useEffect</code>. Consider a component where the user can increment a counter and mark a checkbox in order to display the count in the document&apos;s title.</p>
<pre><code class="language-jsx">import React, { useState, useEffect, useRef } from &apos;react&apos;
import Button from &apos;./Button&apos;

function Counter() {
  const [count, setCount] = useState(0)
  const [checked, setChecked] = useState(false)
  const initialTitleRef = useRef(document.title)

  useEffect(() =&gt; {
    document.title = checked
      ? `Total number of clicks: ${count}`
      : initialTitleRef.current
  }, [checked, count])

  return (
    &lt;div&gt;
      &lt;span data-testid=&quot;count&quot;&gt;
        Clicked {count} time{count === 1 ? &apos;&apos; : &apos;s&apos;}
      &lt;/span&gt;
      &lt;br /&gt;
      &lt;Button onClick={() =&gt; setCount(count + 1)} text=&quot;Increment&quot; /&gt;
      &lt;div&gt;
        &lt;input
          type=&quot;checkbox&quot;
          id=&quot;checkbox-title&quot;
          checked={checked}
          onChange={e =&gt; setChecked(e.target.checked)}
        /&gt;
        &lt;label htmlFor=&quot;checkbox-title&quot;&gt;
          Check to display count in document title
        &lt;/label&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  )
}

export default Counter
</code></pre>
<p>First, let us make sure that the counter works as expected:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import Counter from &apos;./Counter&apos;
import { render, fireEvent, cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

test(&apos;count starts with 0&apos;, () =&gt; {
  const { getByTestId } = render(&lt;Counter /&gt;)
  expect(getByTestId(&apos;count&apos;).textContent).toBe(&apos;Clicked 0 times&apos;)
})

test(&apos;clicking on button increments counter&apos;, () =&gt; {
  const { getByText, getByTestId } = render(&lt;Counter /&gt;)
  fireEvent.click(getByText(&apos;Increment&apos;))
  expect(getByTestId(&apos;count&apos;).textContent).toBe(&apos;Clicked 1 time&apos;)
  fireEvent.click(getByText(&apos;Increment&apos;))
  expect(getByTestId(&apos;count&apos;).textContent).toBe(&apos;Clicked 2 times&apos;)
})
</code></pre>
<p>Nothing really new so far. Time to test the effect:</p>
<pre><code class="language-jsx">...

test(&apos;window title changes after every increment if checkbox is checked&apos;, () =&gt; {
  global.window.document.title = &quot;My Awesome App&quot;;
  const { getByText, getByLabelText } = render(&lt;Counter /&gt;);

  // When checkbox is unchecked, incrementing has no effect
  fireEvent.click(getByText(&quot;Increment&quot;));
  expect(global.window.document.title).toBe(&quot;My Awesome App&quot;);

  // Check and assert the document title changes
  const checkbox = getByLabelText(&quot;Check to display count in document title&quot;);
  fireEvent.click(checkbox);
  expect(global.window.document.title).toBe(&quot;Total number of clicks: 1&quot;);

  // Works if you increment multiple times
  fireEvent.click(getByText(&quot;Increment&quot;));
  expect(global.window.document.title).toBe(&quot;Total number of clicks: 2&quot;);

  // Unchecking will return to the original document title
  fireEvent.click(checkbox);
  expect(global.window.document.title).toBe(&quot;My Awesome App&quot;);
});
</code></pre>
<p>The test should be straightforward to follow. Some remarks:</p>
<ul>
<li>We start by defining <code>document.title</code> in the <code>global.window</code> object. Notice that we initialize it once and then the effect is responsible for further changes;</li>
<li>Even though the checkbox has an <code>onChange</code> event handler, we need to fire a <code>click</code> event;</li>
<li>Differently from the <code>aria-label</code> example in Scenario 2, we now use a <code>label</code> element to select the input.</li>
</ul>
<p>This example is heavy on Hooks. If you want to learn more about them, make sure to check <a href="how-to-reuse-logic-with-react-hooks">How to Reuse Logic with React Hooks</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-5settimeout">Scenario 5 - setTimeout</h2>
<p>All of our examples so far were synchronous, meaning that we didn&apos;t need to wait for anything before checking the result of an operation. From now on, the examples will include async code. Async code is mostly found in timeouts, intervals and API calls.</p>
<p>Let us start with a simple application that should display a message 5 seconds after a button is clicked:</p>
<pre><code class="language-jsx">import React, { useState } from &apos;react&apos;
import useTimeout from &apos;use-timeout&apos;

const TimeoutMessage = () =&gt; {
  const [message, setMessage] = useState(&apos;This will timeout in 5 seconds&apos;)
  useTimeout(() =&gt; setMessage(&apos;Timeout!&apos;), 5000)

  return &lt;div data-testid=&quot;timeout-message&quot;&gt;{message}&lt;/div&gt;
}

export default TimeoutMessage
</code></pre>
<p>First thing we will do is confirm that <code>TimeoutMessage</code> has the expected behavior. It initially displays a message that is changed upon timeout:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import TimeoutMessage from &apos;./TimeoutMessage&apos;
import { render, cleanup } from &apos;@testing-library/react&apos;

jest.useFakeTimers()

afterEach(cleanup)

test(&apos;renders with default text&apos;, () =&gt; {
  const { getByTestId } = render(&lt;TimeoutMessage /&gt;)
  expect(getByTestId(&apos;timeout-message&apos;).textContent).toBe(
    &apos;This will timeout in 5 seconds&apos;
  )
})

test(&apos;text changes after timeout&apos;, () =&gt; {
  const { getByTestId } = render(&lt;TimeoutMessage /&gt;)
  jest.runAllTimers()
  expect(getByTestId(&apos;timeout-message&apos;).textContent).toBe(&apos;Timeout!&apos;)
})
</code></pre>
<p>The key here is to use <a href="https://jestjs.io/docs/en/timer-mocks?ref=rafaelquintanilha.com">Jest timer mocks</a>. We declare <code>jest.useFakeTimers()</code> at the top of the test file and then call <code>jest.runAllTimers()</code> in order to run the timeout.</p>
<p>Now, let us integrate <code>TimeoutMessage</code> into our main <code>Timeout</code> component:</p>
<pre><code class="language-jsx">import React, { useState } from &apos;react&apos;
import TimeoutMessage from &apos;./TimeoutMessage&apos;

const Timeout = () =&gt; {
  const [hasClicked, setHasClicked] = useState(false)
  return (
    &lt;div&gt;
      &lt;button disabled={hasClicked} onClick={() =&gt; setHasClicked(true)}&gt;
        Click to trigger timeout
      &lt;/button&gt;
      {hasClicked &amp;&amp; &lt;TimeoutMessage /&gt;}
    &lt;/div&gt;
  )
}

export default Timeout
</code></pre>
<p>For some extra fun, we also want the button to be disabled once the user has clicked. Now, we have two ways to proceed with the test:</p>
<ol>
<li><code>TimeoutMessage</code> returns a div with <code>data-testid=&quot;timeout-message&quot;</code>. We can create a test that will check that an element with this <code>data-testid</code> is present in the DOM after click. That would be enough to assure that we are rendering <code>TimeoutMessage</code>, however, we wouldn&apos;t have the whole feature (click + timeout message) integrated.</li>
<li>We can assert that the correct messages are being displayed after click and timeout. In the end, that&apos;s what matters. Consider also that <code>TimeoutMessage</code> could be more generic, e.g. accepting two props <code>initialMessage</code> and <code>timeoutMessage</code>, and then it would make sense to check that the right text is displayed.</li>
</ol>
<p>Here&apos;s the integration test:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import Timeout from &apos;./Timeout&apos;
import { render, fireEvent, cleanup } from &apos;@testing-library/react&apos;

afterEach(cleanup)

jest.useFakeTimers()

test(&apos;clicking on button displays timeout message&apos;, () =&gt; {
  const { getByText, queryByTestId, getByTestId } = render(&lt;Timeout /&gt;)
  const button = getByText(&apos;Click to trigger timeout&apos;)
  expect(queryByTestId(&apos;timeout-message&apos;)).toBeNull()
  fireEvent.click(button)
  expect(getByTestId(&apos;timeout-message&apos;).textContent).toBe(
    &apos;This will timeout in 5 seconds&apos;
  )
  jest.runAllTimers()
  expect(getByTestId(&apos;timeout-message&apos;).textContent).toBe(&apos;Timeout!&apos;)
})
</code></pre>
<p><code>Timeout</code> has no knowledge of <code>TimeoutMessage</code>, yet we have asserted that the whole app is integrated.</p>
<p>Finally, we need to confirm that the button is disabled after click:</p>
<pre><code class="language-jsx">...

test(&apos;clicking on button makes it disabled&apos;, () =&gt; {
  const { getByText } = render(&lt;Timeout /&gt;);
  const button = getByText(&quot;Click to trigger timeout&quot;);
  expect(button.disabled).toBeFalsy();
  fireEvent.click(button);
  expect(button.disabled).toBeTruthy();
});
</code></pre>
<p>Again, as <code>button</code> is a regular DOM element, we can access its <code>disabled</code> attribute just fine. Pretty neat!</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-6fetch">Scenario 6 - Fetch</h2>
<p>A very common use case is to assert changes in the UI after data is fetched from an API. This is what we are going to do now. Our next application will fetch a Chuck Norris joke after click and display it to the user. Here&apos;s the <code>Fetch</code> component:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import useAPI from &apos;./useAPI&apos;

const Fetch = () =&gt; {
  const [response, callAPI] = useAPI()
  return (
    &lt;div&gt;
      &lt;button
        onClick={() =&gt; callAPI(&apos;https://api.chucknorris.io/jokes/random&apos;)}
      &gt;
        Get a Chuck Norris joke
      &lt;/button&gt;
      {response.loading &amp;&amp; &lt;div data-testid=&quot;fetch-loading&quot;&gt;Loading...&lt;/div&gt;}
      {response.error &amp;&amp; &lt;div data-testid=&quot;fetch-error&quot;&gt;{response.error}&lt;/div&gt;}
      {response.success &amp;&amp; (
        &lt;div data-testid=&quot;fetch-joke&quot;&gt;{response.data.value}&lt;/div&gt;
      )}
    &lt;/div&gt;
  )
}

export default Fetch
</code></pre>
<p>I&apos;ve used a custom hook called <code>useAPI</code> that returns the response from the server and a function to invoke the API. The implementation of <code>useAPI</code> is out of the scope of this article, but you shouldn&apos;t have any trouble to <a href="https://github.com/rafaelquintanilha/react-testing-library-examples/blob/master/src/useAPI.js?ref=rafaelquintanilha.com">follow along with the source code</a>.</p>
<p>Let&apos;s get to the tests. First thing we want to do is assert that no jokes are displayed when the component renders:</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import Fetch from &apos;./Fetch&apos;
import { render, fireEvent, cleanup, wait } from &apos;@testing-library/react&apos;

afterEach(cleanup)

test(&apos;starts without any joke&apos;, () =&gt; {
  const { queryByTestId } = render(&lt;Fetch /&gt;)
  expect(queryByTestId(&apos;fetch-joke&apos;)).toBeNull()
})
</code></pre>
<p>Recall that we use <code>queyByTestId</code> when we want to assert that an element is <em>not</em> present (<code>getByTestId</code> would throw an error).</p>
<p>Next, let&apos;s write a test to confirm a loading message is displayed after click:</p>
<pre><code class="language-jsx">...

test(&apos;after clicking on button, displays loading message&apos;, () =&gt; {
  const { getByTestId, getByText } = render(&lt;Fetch /&gt;);
  fireEvent.click(getByText(&quot;Get a Chuck Norris joke&quot;));
  expect(getByTestId(&quot;fetch-loading&quot;).textContent).toBe(&quot;Loading...&quot;);
});
</code></pre>
<p>So far so good. But how do we assert the async response?</p>
<p>The answer is the <a href="https://testing-library.com/docs/dom-testing-library/api-async?ref=rafaelquintanilha.com#wait">wait</a> function that comes with RTL. <code>wait</code> allows you to halt the test until the relevant element is visible in the DOM:</p>
<pre><code class="language-jsx{17}">...

test(&apos;after clicking on button, displays joke if API succeeds&apos;, async () =&gt; {
  const joke = &quot;Chuck Norris counted to infinity. Twice.&quot;;

  // Mock API
  jest.spyOn(global, &apos;fetch&apos;)
    .mockImplementation(() =&gt; Promise.resolve({
      status: 200,
      json: () =&gt; Promise.resolve({
        value: joke
      })
    }));

  const { getByTestId, getByText } = render(&lt;Fetch /&gt;);
  fireEvent.click(getByText(&quot;Get a Chuck Norris joke&quot;));
  await wait(() =&gt; getByTestId(&quot;fetch-joke&quot;));

  expect(getByTestId(&quot;fetch-joke&quot;).textContent).toBe(joke);
  expect(global.fetch).toHaveBeenCalledTimes(1);
  expect(global.fetch.mock.calls[0][0]).toBe(&quot;https://api.chucknorris.io/jokes/random&quot;);

  // Clear mock
  global.fetch.mockClear();
});
</code></pre>
<ol>
<li><a href="https://jestjs.io/docs/en/jest-object.html?ref=rafaelquintanilha.com#jestspyonobject-methodname">jest.spyOn</a> mocks the global <code>fetch</code> function. I strongly recommend that you read the docs to get a better sense of how the spy works.</li>
<li><a href="https://jestjs.io/docs/en/mock-function-api.html?ref=rafaelquintanilha.com#mockfnmockimplementationfn">mockImplementation</a> defines which function the spy will invoke. Once <code>fetch</code> returns a Promise that later will be converted to <code>json</code>, we mock the two functions. Also notice that the <code>status</code> is 200 so our <code>useAPI</code> hook doesn&apos;t throw an error.</li>
<li><code>await wait(() =&gt; getByTestId(&quot;fetch-joke&quot;))</code> basically waits for the element with <code>data-testid=&quot;fetch-joke&quot;</code> to become visible in the DOM. This is our async mark.</li>
<li>Now that we have waited for the Promises to resolve and the DOM element to become visible, the next step is as simple as checking that the joke is where it was supposed to be.</li>
<li>Lastly, we assert that we indeed called the right API. <code>mock.calls</code> return an array of calls, each of them composed of an array of args. So <code>mock.calls[0][0]</code> is the first arg of the first call, <code>mock.calls[0][1]</code> is the second arg of the first call and so on.</li>
</ol>
<p>As of now we are able to test the majority of the use cases you will find when developing React applications. But there is one last scenario that I would like to mention.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="scenario-7multiple-api-calls">Scenario 7 - Multiple API calls</h2>
<p>What if you trigger a <em>second</em> API call as a result of the first API call? This is what we are going to see now.</p>
<p>Consider an application that fetches a blog post and, once the post is retrieved, fetches all comments related to the post:</p>
<pre><code class="language-jsx">import React, { useEffect } from &apos;react&apos;
import useAPI from &apos;./useAPI&apos;

const MultipleFetches = () =&gt; {
  const [postResponse, callPostAPI] = useAPI()
  const [commentsResponse, callCommentsAPI] = useAPI()

  useEffect(() =&gt; {
    if (postResponse.success) {
      callCommentsAPI(&apos;https://jsonplaceholder.typicode.com/posts/1/comments&apos;)
    }
  }, [postResponse.success, callCommentsAPI])

  return (
    &lt;div&gt;
      &lt;button
        onClick={() =&gt;
          callPostAPI(&apos;https://jsonplaceholder.typicode.com/posts/1&apos;)
        }
      &gt;
        Fetch post and comments
      &lt;/button&gt;
      &lt;div&gt;
        {postResponse.loading &amp;&amp; (
          &lt;div data-testid=&quot;fetch-loading-post&quot;&gt;Loading post...&lt;/div&gt;
        )}
        {postResponse.error &amp;&amp; (
          &lt;div data-testid=&quot;fetch-error-post&quot;&gt;{postResponse.error}&lt;/div&gt;
        )}
        {postResponse.success &amp;&amp; (
          &lt;div data-testid=&quot;fetch-post&quot;&gt;{postResponse.data.title}&lt;/div&gt;
        )}
      &lt;/div&gt;
      {!postResponse.loading &amp;&amp; (
        &lt;div&gt;
          {commentsResponse.loading &amp;&amp; (
            &lt;div data-testid=&quot;fetch-loading-comments&quot;&gt;Loading comments...&lt;/div&gt;
          )}
          {commentsResponse.error &amp;&amp; (
            &lt;div data-testid=&quot;fetch-error-comments&quot;&gt;
              {commentsResponse.error}
            &lt;/div&gt;
          )}
          {commentsResponse.success &amp;&amp; (
            &lt;ul&gt;
              {commentsResponse.data.slice(0, 10).map(comment =&gt; (
                &lt;li key={comment.id} data-testid=&quot;comment-author&quot;&gt;
                  {comment.name}
                &lt;/li&gt;
              ))}
            &lt;/ul&gt;
          )}
        &lt;/div&gt;
      )}
      {postResponse.success &amp;&amp; commentsResponse.success &amp;&amp; (
        &lt;div data-testid=&quot;multiple-fetch-success&quot;&gt;All fetched!&lt;/div&gt;
      )}
    &lt;/div&gt;
  )
}

export default MultipleFetches
</code></pre>
<p>We now use a combination of <a href="https://github.com/rafaelquintanilha/react-testing-library-examples/blob/master/src/useAPI.js?ref=rafaelquintanilha.com">useAPI</a> and <code>useEffect</code>. Once the first call succeeds, the second API is called. What&apos;s the difference from the single fetch example?</p>
<pre><code class="language-jsx">import React from &apos;react&apos;
import MultipleFetches from &apos;./MultipleFetches&apos;
import { render, fireEvent, cleanup, wait } from &apos;@testing-library/react&apos;

afterEach(cleanup)

describe(&apos;API tests&apos;, () =&gt; {
  // Group API tests so we can clear the mock more easily
  afterEach(() =&gt; global.fetch.mockClear())

  test(&apos;displays post if API succeeds&apos;, async () =&gt; {
    // Mock API
    jest
      .spyOn(global, &apos;fetch&apos;)
      .mockImplementationOnce(() =&gt;
        Promise.resolve({
          status: 200,
          json: () =&gt;
            Promise.resolve({
              title: &apos;How to Become a Bad Developer&apos;,
            }),
        })
      )
      .mockImplementationOnce(() =&gt;
        Promise.resolve({
          status: 200,
          json: () =&gt;
            Promise.resolve([
              { id: 1, name: &apos;Rafael&apos; },
              { id: 2, name: &apos;Andressa&apos; },
            ]),
        })
      )

    const { getByTestId, getByText, getAllByTestId } = render(
      &lt;MultipleFetches /&gt;
    )
    fireEvent.click(getByText(&apos;Fetch post and comments&apos;))

    await wait()

    expect(global.fetch).toHaveBeenCalledTimes(2)
    expect(global.fetch.mock.calls[0][0]).toBe(
      &apos;https://jsonplaceholder.typicode.com/posts/1&apos;
    )
    expect(global.fetch.mock.calls[1][0]).toBe(
      &apos;https://jsonplaceholder.typicode.com/posts/1/comments&apos;
    )

    expect(getByTestId(&apos;fetch-post&apos;).textContent).toBe(
      &apos;How to Become a Bad Developer&apos;
    )
    expect(getByText(&apos;All fetched!&apos;)).toBeTruthy()

    const authors = getAllByTestId(&apos;comment-author&apos;)
    expect(authors[0].textContent).toBe(&apos;Rafael&apos;)
    expect(authors[1].textContent).toBe(&apos;Andressa&apos;)
  })
})
</code></pre>
<p>First, we are now using <a href="https://jestjs.io/docs/en/mock-function-api.html?ref=rafaelquintanilha.com#mockfnmockimplementationoncefn">jest.mockImplementationOnce</a> as we need more control over the fetches (each call should have a different response).</p>
<p>Plus, we use <code>await wait()</code>, with no function as argument. The result of doing that is waiting for the next <em>tick</em> in <a href="https://nodejs.org/fa/docs/guides/event-loop-timers-and-nexttick/?ref=rafaelquintanilha.com">Node event loop</a>. Without going into many details, what it does is to wait until the next async operation is performed.</p>
<p>Once we have awaited the resolution of both calls, the next is easy: just assert that every call was called with the correct API and that the data is being displayed in the DOM.</p>
<p>The full test file including the failure scenarios is <a href="https://github.com/rafaelquintanilha/react-testing-library-examples/blob/master/src/MultipleFetches.test.js?ref=rafaelquintanilha.com">available in GitHub</a>.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>I hope this article helps you when creating tests with Jest and React Testing Library. Don&apos;t forget that you can consult <a href="https://react-testing-library-examples.netlify.com/?ref=rafaelquintanilha.com">React Testing Library Examples</a> as a shorter reference when convenient.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to Become a Bad Developer]]></title><description><![CDATA[Discover the most efficient way to not succeed as a developer.]]></description><link>https://www.rafaelquintanilha.com/how-to-become-a-bad-developer/</link><guid isPermaLink="false">637056c142a473003d9dcad6</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[Best Practices]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Wed, 03 Jul 2019 03:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The great mathematician Carl Jacobi once said <em>&quot;Invert, always invert&quot;</em>. He advocated that, by analyzing a problem backward, one could uncover the best solution to it.</p>
<p>With that in mind, Berkshire Hathway&apos;s legendary partner Charles Munger gave a <a href="http://jameslau88.com/charlie_munger_on_invert_always_invert.htm?ref=rafaelquintanilha.com">terrific speech to the Harvard School</a> on how to <em>not</em> be successful (I originally read this and other Charles&apos; speeches in the amazing <a href="https://www.amazon.com/gp/product/1578645018/ref=as_li_tl?ie=UTF8&amp;tag=rafaelquintan-20&amp;camp=1789&amp;creative=9325&amp;linkCode=as2&amp;creativeASIN=1578645018&amp;linkId=e16372c9ef26ae70461b9916a8a7b3de&amp;ref=rafaelquintanilha.com">Poor Charlie&apos;s Almanack: The Wit and Wisdom of Charles T. Munger</a>). That made me think &#x2013; what is the easiest way to become a <em>bad</em> developer?</p>
<p>What you will see next is a highly subjective, non-exhaustive unordered list of principles that, if you follow, I can guarantee will lead you to become a bad developer. I say &quot;principles&quot; because I am not interested in technicalities (e.g. choose bad variable names, never comment on your code, etc), once they are a sub-product of the guidelines you follow.</p>
<p>If your goal, fellow reader, is to become a good developer instead, don&apos;t worry. Remember that <em>via negativa</em> is way more powerful than <em>via positiva</em>. That means that knowing what <strong>not</strong> to do is safer and easier to figure out than exactly what to do. So pay attention to the following topics and decide which type of developer you want to be.</p>
<h2 id="never-assume-there-is-a-bug-in-your-code">Never assume there is a bug in your code</h2>
<blockquote>
<p>&#x201C;Vanity, definitely my favorite sin.&#x201D; - Al Pacino, Devil&apos;s Advocate</p>
</blockquote>
<p>Software Development is one of the few areas where you have a free pass to make mistakes frequently. This is a very good spot to be if the impact of the mistakes is minimal.</p>
<p>Yet, it is easy to forget that. You can be the best developer in your company and <em>comparatively</em> make fewer mistakes than the others. But the <em>absolute</em> number of mistakes you make will still be high, there&apos;s no escape from it. The good news is that&apos;s fine &#x2013; machines need a lot of precision when communicating and <strong>one bad sentence is enough to blow up a 10,000 LOC codebase</strong>.</p>
<p>But because you consider yourself better than the other developers, which might very well be true, you start to think that you don&apos;t make mistakes. Or that if some issue arose, you have nothing to do with it.</p>
<p>The problem is that many times you will have responsibility. Doesn&apos;t matter if you were the author of the bad code, overlooked it in your review process or didn&apos;t anticipate it when planning. <strong>There are just too many ways of making mistakes</strong>.</p>
<p>So if you never assume that you might have blown things up, you will start blaming other things &#x2013; your peers, the stupid framework you are using, an outdated browser or a pre-historic OS. Anything will be responsible but you. And if you never admit your mistakes, you are cursed to never evolve. And not evolving as a developer is fatal.</p>
<h2 id="write-code-without-reasoning">Write code without reasoning</h2>
<blockquote>
<p>The truth can be perceived only through thinking. - Thomas Aquinas</p>
</blockquote>
<p>One of the first things that we learn as humans belonging to societies is that we need to measure the consequences of our acts. The same applies to programming. Ultimately, your job is to create value for people through lines of code. If you lose track of this, you have become a bureaucrat. And well, it&apos;s pretty hard for a bureaucrat to be a good developer.</p>
<p><strong>If you act without thinking, you are wasting the very edge that you have over machines</strong>. You are a candidate to be replaced in the near future (either by a thoughtful human or by a cheaper dumb machine). Always try to understand what&apos;s the purpose of the task you&apos;ve been assigned to. Unless, of course, you want to become a bad developer.</p>
<h2 id="lack-assertiveness">Lack assertiveness</h2>
<blockquote>
<p>Control your own destiny or someone else will. - Jack Welch</p>
</blockquote>
<p>I am yet to find a good developer who is unable to report the issues he or she is facing with clarity of mind.  This happens because computers are very obedient entities which only function when given precise instructions. If you are assertive when debugging your code, chances are you will figure out the problem by yourself. But even if you don&apos;t, you are halfway through the solution and a fresh pair of eyes will be much more effective in the process of helping you.</p>
<p>Remember that machines are very dumb and need to be correctly told what to do. And that you give them too many instructions during your work. Eventually, you will give the wrong instructions. If you can&apos;t effectively walk through your code and identify the misplaced directives, you will be a bad developer.</p>
<h2 id="take-pleasure-in-writing-more-code">Take pleasure in writing more code</h2>
<blockquote>
<p>&#x201C;Until we have begun to go without them, we fail to realise how unnecessary many things are. We&apos;ve been using them not because we needed them but because we had them.&#x201D; -  Seneca</p>
</blockquote>
<p>It is very common, especially among novice developers, to be proud of the number of lines of code their application has. This is, indeed, a very strong sign that you are in good shape to become a bad developer.</p>
<p>Every line of code is an instruction to a machine. <strong>The greater the number of instructions, the greater the number of mistakes are there to be made</strong>. It also means that you will need more knowledge if you ever want to change how your code behaves. By writing as many lines as possible, you are shielding people from your work. A code that nobody wants to read and many fear touching is a bad code.</p>
<p>I&apos;ve mentioned <em>via negativa</em> before. Simply put, it means &quot;the less, the better&quot;. The reasoning is as follows: <strong>there are many more ways to screw things up than to improve them</strong>. Someone who wants no trouble will focus on minimizing the probability of screwing the codebase, whereas a bad developer will actively look for more additions.</p>
<p>Recall that every line of code will eventually be read, tested, changed, incremented or even deleted. It&apos;s pretty clear that your workload is proportional to the amount of code. Someone who increases his or her workload unnecessarily is just a bad developer.</p>
<h2 id="write-for-machines-not-humans">Write for machines, not humans</h2>
<blockquote>
<p>&#x201C;It has become appallingly obvious that our technology has exceeded our humanity.&#x201D; - Albert Einstein.</p>
</blockquote>
<p>Finally, this is the most efficient way to achieve your goal of being a bad developer. I say that because writing code for machines instead of humans is the easiest of all the bad things you can do. It&apos;s terribly simple to write undocumented code, use inaccurate variable names, be inconsistent, forget about indentation, and so on.</p>
<p>You need to recall that <strong>machines understand machine code</strong>. All other things that are not 1&apos;s and 0&apos;s are just ornament to make code more readable to humans. If you don&apos;t pay attention to this, you are making humans&apos; lives harder &#x2013; thus, a perfect way to be a bad developer.</p>
<p>Think about what makes a text enjoyable to you. It is usually concise, clear, direct, meaningful and consistent. You won&apos;t enjoy reading when you can&apos;t understand the author, the narrative doesn&apos;t make sense, it&apos;s poorly written or weirdly formatted. Likewise, code that does not make sense and that you need to strive to grasp is an excellent form of discouraging the reader. And the same way an author who discourages their readers is a bad author, a developer who discourages their readers is a bad developer.</p>
<hr>
<p>I hope that you find the above rules useful in your quest of becoming a bad developer. But if you ever change your mind and decide to grow into a good one instead, well, you now know what you need to avoid.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to Reuse Logic with React Hooks]]></title><description><![CDATA[Learn why Hooks are a game-changer and write your first hook.]]></description><link>https://www.rafaelquintanilha.com/how-to-reuse-logic-with-react-hooks/</link><guid isPermaLink="false">6370534742a473003d9dca83</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[React]]></category><category><![CDATA[ButterCMS]]></category><dc:creator><![CDATA[Rafael Quintanilha]]></dc:creator><pubDate>Tue, 25 Jun 2019 03:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>React has always been great for reusing and composing <em>components</em>. That means you can write a piece of UI and simply reuse it later on. Moreover, your component can have some embedded logic that you can reuse too. Write once, and use everywhere. A big win!</p>
<p>But what if you want to reuse the logic <em>only</em>? It means that you don&#x2019;t care about the UI, but you care about the behavior of the component. Can you still write it once and use it everywhere?</p>
<p>And the answer is&#x2026; yes! React developers have designed all kinds of patterns for reusing logic, the most prominent being <em>Higher-Order Components (HOC)</em> and <em>Render Props</em>. They work and have been in use for quite a while. But still, those two approaches don&#x2019;t feel quite right and have some shortcomings (which we will see soon). What could be a possible alternative?</p>
<p><a href="https://reactjs.org/blog/2019/02/06/react-v16.8.0.html?ref=rafaelquintanilha.com">As of React 16.8, Hooks were introduced</a>. Hooks are a way to reuse <em>logic</em> across applications. You write a specific behavior (logic) and &#x201C;hook&#x201D; it into any component. This component now can use this logic normally.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="why-do-we-need-react-hooks">Why do we need React Hooks?</h3>
<p>Consider that you want to add a clock into your application. Clearly, you think, this is something very common that someone might have already developed. You find a React library that renders the clock and exposes a few props to customize its style and functionality (size, display seconds or not, frequency of update, etc). After a few tweaks, you have your component pretty similar to what you want, though <em>not quite</em>. Maybe you want to customize only the hours (make it bigger) or add a different color to the minutes. In the end, you wish you could just use the clock <em>logic</em> and style it exactly how you want.</p>
<p>This scenario is a great use case for Hooks. You can &#x201C;hook&#x201D; the &#x201C;clock behavior&#x201D; into a component and have the current time available. Then, you just use the time as you would use any variable declared in the scope of your component, the difference being that you don&#x2019;t need to worry about it (in case you are curious, check the <a href="https://github.com/rafaelquintanilha/use-clock?ref=rafaelquintanilha.com">useClock</a> hook that I developed and that illustrates this principle).</p>
<p>But before diving deeper into Hooks, let us understand the issues with the former solutions.</p>
<h1 id="the-world-before-hooks">The world before Hooks</h1>
<p>We have seen that React is great for reusing UI but that sometimes we might be interested only in the logic behind a component. Hooks are an answer to this demand. Let&#x2019;s examine how we reused logic in the <em>pre</em>-Hooks era.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="higher-order-components-hoc">Higher-Order Components (HOC)</h3>
<p>Probably the first pattern to be widely adopted by the React community on this matter, HOCs, solved the reusable logic problem using <em>composition</em>. Here is the idea: you develop a component that implements the logic and passes the computed values (for example, the current time) to the children, which have access to the values via props. Generically:</p>
<pre><code class="language-jsx">&lt;ComponentWhichImplementsLogic&gt;
  &lt;ComponentWhichUsesLogic /&gt;
&lt;ComponentWhichImplementsLogic&gt;
</code></pre>
<p>Because <code>&lt;ComponentWhichImplementsLogic&gt;</code> is higher in the DOM order, we call them <em>Higher-Order Components</em>. HOCs conventionally start with the <em>with</em> prefix.</p>
<p>We can make them more legible by creating a function that accepts a component and returns this component with the injected logic:</p>
<pre><code class="language-jsx">ComponentWhichImplementsLogic(ComponentWhichUsesLogic)
</code></pre>
<p>Or, recalling our example:</p>
<pre><code class="language-jsx">withClock(MyComponent)
</code></pre>
<p>Considering that <code>withClock</code> is an HOC which implements the clock feature and exposes the current time, <code>MyComponent</code> would then access the current time via props. I won&#x2019;t dive into the specifics of the development, but consider that a <code>withClock</code> component would store the current time in the state, add a <code>setInterval</code> in <code>componentDidMount</code> that increments the time at each interval, and does the proper cleanup when unmounted (calls <code>clearInterval</code>).</p>
<p>The first problem with this approach is that using multiple HOCs starts to become cumbersome. Suppose you also want your component to track the user&#x2019;s current mouse position:</p>
<pre><code class="language-jsx">withMousePosition(withClock(MyComponent))
</code></pre>
<p>And you can certainly imagine why this is suboptimal if the number of injected logic grows. Also, it makes debugging and testing a pain. If your component misbehaves, detecting the flaw in a tree of HOCs won&#x2019;t be pleasant.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="render-props">Render Props</h3>
<p>When people started complaining about the issues of Higher-Order Components, a new pattern emerged: <em>render props.</em> You can read all about it <a href="https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce?ref=rafaelquintanilha.com">in this very popular post by Michael Jackson</a>. Basically, the component which implements the logic receives a <em>render prop</em> and calls it in its <em>own</em> render function, but now exposing the computed values:</p>
<pre><code class="language-jsx">&lt;Clock render={props =&gt; &lt;MyComponent {...props} /&gt;} /&gt;
</code></pre>
<p>This way, whatever props are returned by <code>Clock</code>, will be accessible to <code>MyComponent</code>. The render props pattern avoids some hard to debug issues such as name collision (suppose you accidentally override a prop or state name) and is somewhat less verbose, despite the excess of JSX.</p>
<p>While the community seemed to adopt the render props pattern, composing logic is still suboptimal and some started to complain about the dreaded <a href="https://twitter.com/acdlite/status/955954032194895872?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E955954032194895872&amp;ref_url=https%3A%2F%2Fwww.richardkotze.com%2Fcoding%2Fhoc-vs-render-props-react&amp;ref=rafaelquintanilha.com">callback hell</a>:</p>
<pre><code class="language-jsx">&lt;Clock render={({time}) =&gt; (
  &lt;Mouse render={({x, y}) =&gt; ( 
    &lt;MyComponent time={time} x={x} y={y} /&gt;
  )} /&gt;
)} /&gt;
</code></pre>
<p>This becomes unreadable pretty quickly. Clearly, there is still much room for improvement. Next, we will see what a Hooks approach would look like.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h1 id="the-hooks-solution">The Hooks solution</h1>
<p>While React definitely has alternatives for the reuse of <em>logic</em>, we have seen that it is suboptimal &#x2013; particularly for composition (multiple logic being added to a single component can become too verbose, too hard to debug and too similar to callback hell).</p>
<p>Without further ado, consider how the former example could be written using hooks:</p>
<pre><code class="language-jsx">const MyComponent = () =&gt; {
  const [time] = useClock();
  const [x, y] = useMouseMove();
  // do something with those values
  return (
    &lt;&gt;
      &lt;div&gt;Current time: {time}&lt;/div&gt;
      &lt;div&gt;Mouse coordinates: {x},{y}&lt;/div&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p>That&#x2019;s it! You simply declare your Hooks (in this case, <code>useClock</code> and <code>useMouseMove</code>) and have them instantly available inside your component. There is no extra work. Just plug it (hook) into your component and you are good to go.</p>
<p>Notice that we can use as many Hooks as we want. It is seamlessly composable and trivial to test (forget about a deep tree of nested components and weird inline JSX). And there is more: as you can see in the above example, <em>it works with functional components</em>, which reduces the verbosity of your component considerably (forget about using this or setting up constructors).</p>
<p>Indeed, with the advent of Hooks using class components are somewhat discouraged. <a href="https://reactjs.org/docs/hooks-faq.html?ref=rafaelquintanilha.com#do-hooks-cover-all-use-cases-for-classes">According to the docs</a>, there are just a few edge cases where classes have no Hooks equivalent, so it is very likely that you can start using Hooks right away.</p>
<p>Does that mean that you need to rewrite all your class components using Hooks? <strong>Definitely not</strong>. Hooks are a powerful solution and it is being well received by the community. However, by no means feel like you should do a major rewrite just because of that.</p>
<p>With that being said, let&#x2019;s understand the main differences between classes and Hooks.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="the-mental-model">The Mental Model</h3>
<p>One of the biggest distinctions between classes and Hooks is that <em>Hooks have no lifecycles</em>. For experienced React developers, this can take some time to click. We are used to thinking in terms of <code>componentDidMount</code>, <code>componentWillUpdate</code>, etc. But with Hooks things don&#x2019;t work this way.</p>
<p>So the first thing you need to avoid is trying to map a given lifecycle to a particular use case with Hooks. This will only confuse you. Instead, just think that for Hooks any state or prop change calls the function again (recall your component is a function) with the updated values (state and props). For peace of mind, <a href="https://reactjs.org/docs/hooks-faq.html?ref=rafaelquintanilha.com#how-do-lifecycle-methods-correspond-to-hooks">the docs give you a rough equivalency</a> of certain lifecycles in the Hooks world.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">&quot;[...] Hooks have no lifecycles. For experienced React developers, this can take some time to click. We are used to thinking in terms of componentDidMount, componentWillUpdate, etc. But with Hooks things don&#x2019;t work this way.&quot;<br><br>My article on learning <a href="https://twitter.com/reactjs?ref_src=twsrc%5Etfw&amp;ref=rafaelquintanilha.com">@reactjs</a> Hooks &#x1F447; <a href="https://t.co/8o6tUHkuDE?ref=rafaelquintanilha.com">https://t.co/8o6tUHkuDE</a></p>&#x2014; Rafael Quintanilha (@webquintanilha) <a href="https://twitter.com/webquintanilha/status/1140811628398743553?ref_src=twsrc%5Etfw&amp;ref=rafaelquintanilha.com">June 18, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><!--kg-card-begin: markdown--><p>One of the core contributors to React, Dan Abramov, wrote in his blog <a href="https://overreacted.io/how-are-function-components-different-from-classes/?ref=rafaelquintanilha.com">a piece on the differences between function and class components</a>. Go check it out if you are curious about the internals.</p>
<p>Now that we understand that Hooks do not operate based on lifecycles (like classes do), let&#x2019;s examine how the most common Hooks work.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="usestate">useState</h3>
<p>The first and simplest Hook is <code>useState</code>. Basically, it does exactly what you would expect: you declare a variable and a setter. Here&#x2019;s how it looks:</p>
<pre><code class="language-jsx">import React, { useState } from &apos;react&apos;;

const Counter = () =&gt; {
  const [count, setCount] = useState(0);
  return (
    &lt;div&gt;
      &lt;div&gt;Current count: {count}&lt;/div&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;Increment&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>As you can see, the hook returns an array with two elements and takes one parameter.</p>
<ul>
<li>The first element of the array is the current value for this state;</li>
<li>The second element of the array is a setter that changes the value of this state;</li>
<li>The parameter used in the hook (in our example, 0) is the initial value of this state.</li>
</ul>
<p>Naturally, you can add multiple states by adding multiple hooks:</p>
<pre><code class="language-jsx">const Counter = () =&gt; {
  const [count, setCount] = useState(0);
  const [step, setStep] = useState(1);
  return (
    &lt;div&gt;
      &lt;div&gt;Current count: {count}&lt;/div&gt;
      &lt;button 
        onClick={() =&gt; setCount(count + step)}&gt;
        Increment by {step}
      &lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>Now recall that with Hooks every re-render is nothing else than the function being called again (in our example, <code>Counter</code>). But for every re-render, the state will be updated with its current value. This is the main difference between a state variable and a regular variable. Regular variables will always be re-defined.  State variables will be derived from the previous state.</p>
<p>How do we trigger a re-render? Every time a prop or state variable changes we trigger a re-render.  This is done by invoking the setter, in our example through the click of the button. This is important to know so we can better understand the next Hook.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="useref">useRef</h3>
<p>Sometimes we want to store a value in our component for future reference, but we don&#x2019;t want to trigger a re-render (as this value isn&#x2019;t expected to change often or has little or no UI impact). This would be the equivalent of having a class property:</p>
<pre><code class="language-jsx">this.myValue = value;
</code></pre>
<p>To address this case, <code>useRef</code> was introduced. Refs give us a way to store a variable in the scope of the function and preserve its value across renders. One typical case is to set a reference into an HTML component:</p>
<pre><code class="language-jsx">import React, { useRef } from &apos;react&apos;;

const FocusInput = () =&gt; {
  const inputRef = useRef(null);
  const onClick = () =&gt; inputRef.current.focus();
  return (
    &lt;div&gt;
      &lt;input ref={inputRef} /&gt;
      &lt;button onClick={onClick}&gt;Focus&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>Notice that <code>useRef</code> receives an initial value (in our example, <code>null</code>) and returns the ref variable. Whatever is stored in this ref can be accessed via <code>myRef.current</code>, so when we assign the ref of the input element to <code>inputRef</code>, <code>inputRef.current</code> holds the actual DOM element, allowing us to programmatically trigger focus.</p>
<p>In fact, <code>useRef</code> is a special case of <code>useState</code>, but one that we set its value directly instead of using a setter, which persists the value across renders without triggering a re-render.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">useRef vs useState<br><br>What&apos;s the difference between the two Hooks?<br><br>useRef is a special case of useState: <a href="https://t.co/Y2tCnuBeQZ?ref=rafaelquintanilha.com">https://t.co/Y2tCnuBeQZ</a><br><br>- useRef persists values across re-renders<br>- changing useRef does not trigger a re-render<br><br>More about <a href="https://twitter.com/hashtag/hooks?src=hash&amp;ref_src=twsrc%5Etfw&amp;ref=rafaelquintanilha.com">#hooks</a>: <a href="https://t.co/7MRBkpAHXL?ref=rafaelquintanilha.com">https://t.co/7MRBkpAHXL</a></p>&#x2014; Rafael Quintanilha (@webquintanilha) <a href="https://twitter.com/webquintanilha/status/1138915113824595968?ref_src=twsrc%5Etfw&amp;ref=rafaelquintanilha.com">June 12, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><!--kg-card-begin: markdown--><p>If you want to learn refs in depth, <a href="https://www.rafaelquintanilha.com/the-complete-guide-to-react-refs/">The Complete Guide to React Refs</a> has a comprehensive coverage of how refs work.</p>
<p>So far we have learned how to manipulate variables inside a component using Hooks. We are still missing how to respond to some events. For example, how can I fetch data from an API when the component mounts, or how can I perform an operation if a particular state changed?</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="useeffect">useEffect</h3>
<p>The <code>useEffect</code> hook can be tricky to grasp, particularly if you think too much in terms of old React class lifecycles. It has some subtleties that are not immediate but definitely make sense. Let us start from the beginning: what exactly is an effect?</p>
<blockquote>
<p>An <em>effect</em>, or <em>side effect</em>, is an operation that you run after a render.</p>
</blockquote>
<p>A practical example: suppose you have a component that fetches a list of products for a given category. Once your component renders (&#x201C;mounts&#x201D;) you want to trigger the API call. And if later the category changes (for example if the user navigates from the sports section to the fashion section of an e-commerce site), you want to call the API again.</p>
<p>Notice that with what we learned about <code>useState</code> and <code>useRef</code> we are unable to do so. We currently haven&#x2019;t learned a way to only perform operations given that certain things happened to our state or props.</p>
<p>In the old-style class component, our example would look like this:</p>
<pre><code class="language-jsx">class ProductsList extends React.Component {
  componentDidMount() {
    this.getProducts()
  }

  componentDidUpdate(prevProps) {
    if ( prevProps.categoryId !== this.props.categoryId ) {
      this.getProducts();
    }
  }

  getProducts() {
    // perform API call with this.props.categoryId
  }

  ...
}
</code></pre>
<p>Now, what is the Hooks equivalent?</p>
<pre><code class="language-jsx">const ProductsList = props =&gt; {
  const getProducts = () =&gt; {
    // perform API call with props.categoryId
  }

  useEffect(() =&gt; {
    getProducts();
  });

  ...
}
</code></pre>
<p>This looks way cleaner. We define an <em>effect</em> which accepts a function that will be called after render and then will perform some operation (here, call <code>getProducts</code>). However, this isn&#x2019;t quite right yet. The above code runs the effect after every render. How can we fix that?</p>
<p>Luckily, <code>useEffect</code> accepts a dependency array. It means that you can declare upon which state or props change you want to trigger the effect. For us, it would look like this:</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
  getProducts();
}, [props.categoryId]);
</code></pre>
<p>The above code will run after the first render and in all renders caused by a change in <code>props.categoryId</code>. It is a combination of <code>componentDidMount</code> and <code>componentDidUpdate</code>.</p>
<p>What if you want to call the effect only on &#x201C;mount&#x201D; (or in Hooks jargon, after the first render)?</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
  getProducts();
}, []);
</code></pre>
<p>The answer is to make the dependency array an empty one. Remember that when we add a dependency array, the effect gets called after the first render and whenever any of the values in the array change. Logically, if there is no element in the array, it will only be called after the first render.</p>
<p>If you want to run your effect after every render, simply remove the dependency array at all (like in our first example). However, make sure you know what you are doing because this can cause performance issues (imagine calling an API whenever a component with plenty of states and props re-renders).</p>
<p>There is one last thing that I want to mention about <code>useEffect</code>. Sometimes you might want to do a cleanup, the equivalent of the <code>componentWillUnmount</code> lifecycle. For example, you might have added a DOM listener that you want to remove upon unmount. Recall our <code>useMouseMove</code> hook? Here is how we can implement it with Hooks using what we have learned so far:</p>
<pre><code class="language-jsx">import React, { useState, useEffect } from &apos;react&apos;;

const useMouseMove = () =&gt; {
  const [coords, setCoords] = useState([0, 0]);

  useEffect(() =&gt; {
    const handler = ({ clientX, clientY }) =&gt; {
      setCoords([clientX, clientY]);
    };
    window.addEventListener(&apos;mousemove&apos;, handler);
    return () =&gt; {
      window.removeEventListener(&apos;mousemove&apos;, handler);
    };
  }, []);

  return coords;
};
</code></pre>
<p><a href="https://github.com/donavon/use-event-listener?ref=rafaelquintanilha.com">The above is outlined in the terrific use-event-listener library</a>. After the first render, you add a listener to the window object and call a cleanup function when the component is removed from the DOM. Whatever function you return from inside your effect will be called upon unmount. <a href="https://reactjs.org/docs/hooks-effect.html?ref=rafaelquintanilha.com#effects-with-cleanup">The official docs</a> provide more details if you want to dive deeper.</p>
<p>Finally, in the Overreact blog by Dan Abramov, <a href="https://overreacted.io/a-complete-guide-to-useeffect/?ref=rafaelquintanilha.com">there is a comprehensive guide</a> of <code>useEffect</code>. The post is very long but I encourage you to find some time and read it if you want to master <code>useEffect</code>.</p>
<h3 id="other-hooks">Other Hooks</h3>
<p>There are several other built-in Hooks in the new API. All of them are described in the <a href="https://reactjs.org/docs/hooks-reference.html?ref=rafaelquintanilha.com">API reference</a>, but I will highlight some:</p>
<h4 id="usecontext">useContext</h4>
<p>Equivalent to the <a href="https://reactjs.org/docs/context.html?ref=rafaelquintanilha.com">Context API</a>. Allows your component to read from a Context:</p>
<pre><code class="language-jsx">const value = useContext(MyContext);</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="usereducer">useReducer</h4>
<p>For some time, state management libraries such as Redux were a controversial point in the React community. They evolved over the years but the hype has been diminishing. Hooks, however, provide a very neat way to add a reducer to your component.</p>
<p>A <em>reducer</em> is basically a function that accepts a state and an action. Based on the action, it updates the state. This leads the developer to a better encapsulation of the state, while increasing the maintainability of the state as it grows. <a href="https://reactjs.org/docs/hooks-reference.html?ref=rafaelquintanilha.com#usereducer">More about useReducer in the docs</a>.</p>
<h4 id="usecallback">useCallback</h4>
<p>The last built-in Hook that I want to mention is <code>useCallback</code>. Basically, <code>useCallback</code> receives a function and a dependency array and memoizes that function until any of its dependencies change. It is useful for optimizations and borrows the <code>shouldComponentUpdate</code> mindset.</p>
<p>Suppose you render a <code>Button</code> component:</p>
<pre><code class="language-jsx">const Component = () =&gt; {
  const onClick = () =&gt; console.log(&#x201C;Clicked&#x201D;);
  return &lt;Button onClick={onClick}&gt;Click&lt;/Button&gt;;
}
</code></pre>
<p>Whenever <code>Component</code> re-renders, <code>onClick</code> will be redefined (recall that we call the function scope every render). Once <code>onClick</code> essentially changed, <code>Button</code> will re-render too. But notice that <code>onClick</code> is in practice the same function, so we re-rendered <code>Button</code> unnecessarily!</p>
<pre><code class="language-jsx">const Component = () =&gt; {
  const onClick = useCallback(() =&gt; console.log(&#x201C;Clicked&#x201D;), []);
  return &lt;Button onClick={onClick}&gt;Click&lt;/Button&gt;;
}
</code></pre>
<p>The above code fixes our problem. By wrapping our function in <code>useCallback</code> we now have it memoized and only recreated if any value in the dependency array changes (in our case, because <code>useCallback</code> has no dependencies, it will never change).</p>
<p><code>useCallback</code> is very related to <code>useMemo</code>, which does basically the same thing, but memoizing the <em>result</em> of a function, not the function itself. There is a nice piece about their differences in this <a href="https://stackoverflow.com/a/54963730/4487722?ref=rafaelquintanilha.com">Stack Overflow comment</a>.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="next">Next</h4>
<p>We have covered everything we needed (much more, in fact) to write our first hook. So the next section will stop the theory and explain how we can create a custom hook for ourselves.</p>
<h1 id="writing-your-first-hook">Writing your first hook</h1>
<p>So far we learned how to use Hooks to achieve the same things we would achieve with a class component. But recall that the greater goal of Hooks is to make logic <em>shareable</em>, so this is our next objective.</p>
<p>We saw a sneak peek of this process in the <code>useMouseMove</code> hook provided in the last section. Basically, we wrote a function that used some hooks (<code>useState</code> and <code>useEffect</code>) and returned a value.</p>
<p>For this section, we will write a <code>useButter</code> hook. This hook will make our life easier when injecting ButterCMS data in any component. <a href="https://buttercms.com/api-first-cms/?ref=rafaelquintanilha.com">ButterCMS is a headless Content Management System that you can learn more about here</a>. Let&#x2019;s get started writing our <code>useButter</code> hook.</p>
<h3 id="modeling-the-api">Modeling the API</h3>
<p><a href="http://buttercms.com/docs/api-client/react?ref=rafaelquintanilha.com#Quickstart">Butter docs</a> cover all you need to know about using Butter in a React application. In short, once you have your Butter client set with the correct API key, listing the first 10 posts of your blog is as easy as:</p>
<pre><code class="language-jsx">butter.post.list({page: 1, page_size: 10}).then(function(response) {
  console.log(response);
});
</code></pre>
<p>Notice that the butter client exposes us to some entities (in this example, <em>page</em>) and a few methods (in this example, <em>list</em>). Finally, we can also pass some options (in this example, the number of pages and the page size) and after the API resolves, access the response. <a href="https://buttercms.com/docs/api/?javascript=&amp;ref=rafaelquintanilha.com#introduction">Check the API reference</a> for a complete list of entities and methods.</p>
<p>Ideally, our hook would receive the entity, method, and options, and return the API response. To give us more control over the network request, we will also need to know if the API is still loading or if it failed.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="creating-the-hook">Creating the Hook</h3>
<p>Let us now start creating our hook. All code in this article is present in <a href="https://github.com/rafaelquintanilha/butter-hooks-example?ref=rafaelquintanilha.com">this GitHub repo</a>. Afterward, we will build a simple app that fetches posts from the ButterCMS API. <a href="https://butter-hooks-example.netlify.com/?ref=rafaelquintanilha.com">Here&#x2019;s a live preview</a>.</p>
<h4 id="setting-up-butter">Setting up Butter</h4>
<p>First, we will set up Butter and create the hook. When it&#x2019;s done we then &#x201C;hook&#x201D; it into our component.</p>
<p>Go ahead and create your app. For the sake of this example, I&#x2019;ll use <a href="https://facebook.github.io/create-react-app/?ref=rafaelquintanilha.com">create-react-app</a>:</p>
<pre><code>npx create-react-app butter-hooks-example
</code></pre>
<p>Then, navigate to the newly created <em>butter-hooks-example</em> directory and add the butter library:</p>
<pre><code>yarn add buttercms
</code></pre>
<p>Once it&#x2019;s done, create a file in the <em>src</em> folder called <em>butter-client.js</em> and add the following:</p>
<pre><code class="language-jsx">import Butter from &apos;buttercms&apos;;

const butter = Butter(&lt;YOUR API KEY HERE&gt;);

export default butter;
</code></pre>
<p>Make sure to insert your own API key. That&#x2019;s all you need to start communicating with the Butter API.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="usebutter">useButter</h4>
<p>In the same <em>src</em> directory create a file called <em>useButter.js</em>, where our hook will live. Go ahead and add this basic skeleton:</p>
<pre><code class="language-jsx">import butter from &apos;./butter-client&apos;;

const useButter = () =&gt; {

}

export default useButter;
</code></pre>
<p>We now need to add the functionality of our hook. Recall that we decided to return the API response and control variables that determine if the API is loading or if it failed. It makes sense to create them as state variables, so add the following:</p>
<pre><code class="language-jsx">import { useState } from &apos;react&apos;;
import butter from &apos;./butter-client&apos;;

const useButter = () =&gt; {
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(&quot;&quot;);
  // do something with them
  return { response, loading, error };
}

export default useButter;
</code></pre>
<p>We declared three different state variables, each with different initial values. In the end, we return them in the form of an object.</p>
<p>Now, I want to give the user the ability to control when to call the API. Therefore, we need to expose the API call. Let us create the <code>callAPI</code> function:</p>
<pre><code class="language-jsx">...
const callAPI = async (entity, method, ...options) =&gt; {
  if ( butter[entity] === undefined || 
       butter[entity][method] === undefined ) {
    setError(`Unable to call method ${method} from entity ${entity}`);
    return;
  }
  setError(null);
  setLoading(true);
  try {
    const response = await butter[entity][method](...options);
    setResponse(response);
  } catch (e) {
    setError(`${e.status}: ${e.statusText}`);
  }
  setLoading(false);  
}
...
</code></pre>
<p>Recall that the butter client needs an <em>entity</em> and a <em>method</em> (e.g. <em>post</em> and <em>list</em>). The above code checks if, for a given <em>entity</em> and <em>method</em>, the function exists (setting an error if not true). After, we change the state to inform that the API is loading and await the response from the API, we make sure we pass the correct options to the butter client. If it fails, we set the error message and if it works, we set the response. Pretty neat.</p>
<p>The complete code for the hook is:</p>
<pre><code class="language-jsx">import { useState } from &apos;react&apos;;
import butter from &apos;./butter-client&apos;;

const useButter = () =&gt; {
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(&quot;&quot;);

  const callAPI = async (entity, method, ...options) =&gt; {
    if ( butter[entity] === undefined || 
         butter[entity][method] === undefined ) {
      setError(`Unable to call method ${method} from entity ${entity}`);
      return;
    }
    setError(null);
    setLoading(true);
    try {
      const response = await butter[entity][method](...options);
      setResponse(response);
    } catch (e) {
      setError(`${e.status}: ${e.statusText}`);
    }
    setLoading(false);  
  }

  return [{ response, loading, error }, callAPI];
}

export default useButter;
</code></pre>
<p>Notice that we need to make <code>callAPI</code> available in the component, so we pass it alongside with the state object in the form of an array.</p>
<p>This should be enough for us to start hooking things around.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="hooking-up">Hooking up</h3>
<p>With our hook ready it is time to finally see it in action. Go to <code>App.js</code> and add the following:</p>
<pre><code class="language-jsx">import React, { useEffect } from &apos;react&apos;;
import useButter from &apos;./useButter&apos;;
import &apos;./App.css&apos;;

function App() {
  const [{ response, loading, error }, callAPI] = useButter();

  useEffect(() =&gt; {
    callAPI(&apos;post&apos;, &apos;list&apos;, { page: 1, page_size: 10 });
  }, []);

  return (
    &lt;div className=&quot;container&quot;&gt;
      &lt;h1&gt;useButter Example&lt;/h1&gt;
      {loading &amp;&amp; &lt;div&gt;Loading from API...&lt;/div&gt;}
      {error &amp;&amp; &lt;div&gt;There was an error: {error}&lt;/div&gt;}
      {response &amp;&amp; !error &amp;&amp; !loading &amp;&amp; &lt;div&gt;
        &lt;h2&gt;Posts List&lt;/h2&gt;
        &lt;ul&gt;
          {response.data.data.map((post, i) =&gt; (
            &lt;li key={i}&gt;{post.title}&lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;}
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<p>If you save your project and run yarn start you will see your hook in action. Congratulations!</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/ButterCMS---First-Hook-Example.gif" class="kg-image" alt loading="lazy" width="423" height="281"><figcaption>First hook example</figcaption></figure><!--kg-card-begin: markdown--><p>Notice that it loads all posts that I have saved in my account at this moment. Yours will vary.</p>
<p>Remember that I left the usage of the hook to the user. We did this by calling the API after the first render:</p>
<pre><code class="language-jsx">const [{ response, loading, error }, callAPI] = useButter();
useEffect(() =&gt; {
  callAPI(&apos;post&apos;, &apos;list&apos;, { page: 1, page_size: 10 });
}, []);
</code></pre>
<p>What if we want to make the <code>page_size</code> configurable? Let&#x2019;s go ahead and add an input to control this value. First, include the <code>useState</code> hook:</p>
<pre><code class="language-jsx">import React, { useEffect, useState } from &apos;react&apos;;
...

function App() {
  const [pageSize, setPageSize] = useState(10);
  const [{ response, loading, error }, callAPI] = useButter();

  useEffect(() =&gt; {
    callAPI(&apos;post&apos;, &apos;list&apos;, { page: 1, page_size: pageSize });
  }, [pageSize]);
  ...
</code></pre>
<p>Now our effect will re-run every time <code>pageSize</code> changes (once it is in the dependency array). Let&#x2019;s add the appropriate UI:</p>
<pre><code class="language-jsx">...
return (
  &lt;div className=&quot;container&quot;&gt;
    &lt;h1&gt;useButter Example&lt;/h1&gt;
    {loading &amp;&amp; &lt;div&gt;Loading from API...&lt;/div&gt;}
    {error &amp;&amp; &lt;div&gt;There was an error: {error}&lt;/div&gt;}
    {response &amp;&amp; !error &amp;&amp; !loading &amp;&amp; &lt;div&gt;
      &lt;h2&gt;Posts List&lt;/h2&gt;
      &lt;ul&gt;
        {response.data.data.map((post, i) =&gt; (
          &lt;li key={i}&gt;{post.title}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
      &lt;div&gt;
        &lt;label&gt;Page Size&lt;/label&gt;
        &lt;br /&gt;
        &lt;input
          autoFocus
          value={pageSize} 
          onChange={e =&gt; setPageSize(e.target.value)} 
          type=&quot;number&quot;
        /&gt;
      &lt;/div&gt;
    &lt;/div&gt;}
  &lt;/div&gt;
);
...
</code></pre>
<p>Here&#x2019;s the final result:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://www.rafaelquintanilha.com/content/images/2022/11/ButterCMS---Second-Hook-Example.gif" class="kg-image" alt loading="lazy" width="423" height="281"></figure><!--kg-card-begin: markdown--><p>And that&#x2019;s it! We have created a hook that shares logic with any component. Write once, use it everywhere.</p>
<h4 id="fixing-the-dependency-array">Fixing the dependency array</h4>
<p>If you have <a href="https://eslint.org/?ref=rafaelquintanilha.com">ESLint</a> configured, you will see the following warning:</p>
<blockquote>
<p>React Hook useEffect has a missing dependency: &apos;callAPI&apos;. Either include it or remove the dependency array  react-hooks/exhaustive-deps</p>
</blockquote>
<p>What exactly does that mean? Recall our <code>useEffect</code> hook:</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
  callAPI(&apos;post&apos;, &apos;list&apos;, { page: 1, page_size: pageSize });
}, [pageSize]);
</code></pre>
<p>Notice that <code>callAPI</code> is a dependency of the effect as much as <code>pageSize</code>. Even though we don&#x2019;t expect it to change, it is a good practice to list all dependencies in the dependency array. Let&#x2019;s fix it:</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
  callAPI(&apos;post&apos;, &apos;list&apos;, { page: 1, page_size: pageSize });
}, [callAPI, pageSize]);
</code></pre>
<p>If you save your project and check it, you will see that there is an infinite loop going on. What&#x2019;s happening?</p>
<p>Remember that our hook returns <code>callAPI</code>. So every time we call the API, it updates the state and the hook returns a new value. But <code>callAPI</code> is a new definition of the function (even though they are essentially the same) and therefore we trigger the effect again!</p>
<pre><code class="language-jsx">return [{ response, loading, error }, callAPI];
</code></pre>
<p>So in every state change we redefine <code>callAPI</code>.  This is something we don&#x2019;t want to do. Luckily, this is the exact case where <code>useCallback</code> is valuable: we want a function to persist unless some of its dependencies change. Because <code>callAPI</code> has no dependency, we don&#x2019;t need it to ever change.</p>
<p>To fix this, go back to <code>useButter.js</code>, make sure you add <code>useCallback</code> along with <code>useState</code> and change the return statement to:</p>
<pre><code class="language-jsx">return [{ response, loading, error }, useCallback(callAPI, [])];
</code></pre>
<p>And that&#x2019;s it! Now <code>callAPI</code> won&#x2019;t be redefined at every render. Save and see that it is working again.</p>
<h1 id="wrapping-up">Wrapping up</h1>
<p>In this article we learned what Hooks are and that they are meant to solve problems that have been a pebble in the shoes of the React community for a long time &#x2014; how to easily reuse logic in between components instead of UI.</p>
<p>Hooks are an alternative to Higher-Order Components and Render Props, both with their pros and cons. Moreover, Hooks provide a way to map behaviors of class components to functional components (though they do not map directly).</p>
<p>Even though you can do (almost) everything classes do with Hooks, you don&#x2019;t need to switch right away. Instead, try playing around with it until you feel comfortable. Although this is always a matter of personal opinion, I&#x2019;d say Hooks are here to stay, not because of the hype, but ultimately because they are <em>better</em>.</p>
<p>Finally, we saw how to create your own Hook. <code>useButter</code> is an alternative to reuse logic when injecting <a href="http://buttercms.com/?ref=rafaelquintanilha.com">ButterCMS</a> data in your application. It makes accessing the API trivial and handles network requests. There is still room for improvement, so feel free to tweak my code and <a href="https://github.com/rafaelquintanilha/butter-hooks-example?ref=rafaelquintanilha.com">contribute in GitHub</a>!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>