📄 Page
1
(This page has no text content)
📄 Page
2
Praise for Fluent React Carl Sagan once said, “You have to know the past to understand the present.” In my humble opinion, this book is nothing but Tejas bringing this mantra into the frontend realm by guiding us through the historical journey of React. With meticulous detail, he provides an in-depth overview of the key concepts behind reconciliation and Fiber. This is a must-read for anyone seeking a deeper comprehension of React and its ever-evolving ecosystem. —Matheus Albuquerque Brasil, Google Developer Expert in Web Technologies This book made me question everything I thought I knew about React! It is exactly the type of content expected from Tejas: an in-depth journey through the history and internals of React that everyone can understand. If you want to reinforce and grow your knowledge of React, then this book will be your new best friend! —Daniel Afonso, Developer Advocate, OLX The most in-depth explanation of React and how it works I have ever seen. Every React developer should read this book to learn the framework inside out. And I’m not saying this for the sake of a beautiful praise quote! —Sergii Kirianov, Developer Advocate, Vue Storefront Tejas Kumar’s Fluent React has not only deepened my grasp of complex concepts like hydration, memoization, and server components but has also honed my ability to strategize my code’s behavior, enhancing my development process even before the first line is written. —Kenneth Quiggins, Software Developer
📄 Page
3
Where most React books only teach you how to use React, this book teaches how React works. Tejas has done a great job to also cover the difficult details most other authors just gloss over. Not only that, but he also put himself in the vulnerable position to have some of the greatest of the community review his work, learned from them, and put that new knowledge back into the book. Big kudos to him!” —Lenz Weber-Tronic, Comaintainer of Apollo Client & Redux Toolkit
📄 Page
4
Fluent React Build Fast, Performant, and Intuitive Web Applications Tejas Kumar Foreword by Kent C. Dodds
📄 Page
5
Fluent React by Tejas Kumar Copyright 2024 Tejas Kumar. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com. Acquisition Editor: Amanda Quinn Development Editor: Shira Evans Production Editor: Beth Kelly Copyeditor: Sonia Saruba Proofreader: Piper Editorial, LLC Indexer: Potomac Indexing, LLC Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea February 2024: First Edition Revision History for the First Edition
📄 Page
6
2024-02-13: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781098138714 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Fluent React, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the author and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. 978-1-098-13871-4 [LSI]
📄 Page
7
Foreword There is so much you need to understand as a web developer to build applications that users will love. In the React space in particular, there’s a wealth of material available to you, and that’s part of the problem. Not all of it is consistent, and you have to make your own path wading through all of the tutorials and blog posts available, hoping you’ll piece together a curriculum that is free of contradictions and won’t leave gaping holes in your knowledge. And you’ll always worry that what you’re learning is out of date. This is where Tejas Kumar comes in with this book. Tejas has had years of React experience and has gone to great lengths to go in depth on topics that will give you a solid foundation of knowledge. He’s an experienced engineer and fountain of knowledge that will help you feel confident with React. I have been blessed to associate with Tejas over the years in various capacities in open source, conference speaking, educational content creation, and on a personal level, and I hope you understand you hold in your hand a book that has been crafted by a talented individual who is also a fantastic person. In this book, you’ll dive into subjects you would likely not otherwise be exposed to that will help you “think in React” with the proper mental model. You’ll come to understand the purpose of React’s existence in the first place, which will give you a good frame of reference when considering React as a tool to solve problems. React wasn’t invented in a vacuum, and understanding the origin story will help you know the problems React is intended to solve so you can avoid putting a round peg in a square hole. You will understand foundational concepts like JSX, the virtual DOM, reconciliation, and concurrent React, which will help you use this tool more efficiently. I’ve always believed that the best way to level up your experience with a tool is to understand how the tool works. So even if you’ve been using React for years at this point, these sections will open your mind to new possibilities and understanding as you come to really understand React, rather than just piecing things together and hoping (fingers crossed) the result is positive.
📄 Page
8
You’ll discover patterns that the pros use to build effective and powerful abstractions. React itself is a very fast UI library, but there are times when you’re building complex applications that you’ll need to reach for performance optimizations, and Tejas will show you how with the memoization, lazy loading, and state management techniques available in React. Beyond that, you’ll understand how the best libraries in the ecosystem work with patterns like compound components, render props, prop getters, state reducers, and control props. These are critical tools in your tool belt as you build React applications. Even if you’re just using off- the-shelf solutions, understanding how those powerful abstractions work will help you use them more effectively. Tejas goes beyond theoretical React though, and you’ll be introduced to practical frameworks like Remix and Next.js that will be important for you to take advantage of React’s full stack capabilities to make the best user experience possible. With React’s server rendering capabilities since the beginning, you can take control of your own destiny as you use React to build your entire user experience on both the frontend and the backend. And you’ll also get to know the leading edge tech, like Server Components and Server Actions, that React is using to level up the user experience. I’m confident that after reading what Tejas has put together for you, you’ll have the knowledge you need to be successful at building exceptional applications with React. I wish you the very best on your learning experience with React, the most widely used UI library in the world. Enjoy the journey! Kent C. Dodds https://kentcdodds.com
📄 Page
9
Preface This book is not for people who want to learn how to use React. If you’re unfamiliar with React and looking for a tutorial, a great place to start is the React documentation over at react.dev. Instead, this book is for the curious: people who aren’t as interested in how to use React, but who are more interested in how React works. In our time together, we will go on a journey through a number of React concepts and understand their underlying mechanism, exploring how it all fits together to enable us to create applications using React more effectively. In our pursuit of understanding the underlying mechanism, we will develop the mental models necessary to reason about React and its ecosystem with a high degree of fidelity. This book assumes we have a satisfactory understanding of this statement: browsers render web pages. Web pages are HTML documents that are styled by CSS and made interactive with JavaScript. It also assumes we’re somewhat familiar with how to use React, and that we’ve built a React app or two in our time. Ideally, some of our React apps are in production. We’ll start with an introduction to React and recap its history, casting our minds back to 2013 when it was first released as open source software. From there, we’ll explore the core concepts of React, including the component model, the virtual DOM, and reconciliation. We’ll dive into the compiler theory of how JSX works, talk about fibers, and understand its concurrent programming model in depth. This way we’ll glean powerful takeaways that will help us more fluently memoize what ought to be memoized and defer rendering work that ought to be deferred through powerful primitives like React.memo and useTransition. In the second half of this book, we’ll explore React frameworks: what problems they solve, and the mechanisms by which they solve them. We’ll do so by writing our own framework that solves three salient problems
📄 Page
10
across nearly all web applications: server rendering, routing, and data fetching. Once we solve these problems for ourselves, understanding how frameworks solve them becomes far more approachable. We’ll also dive deep into React Server Components (RSCs) and server actions, understanding the role of next-generation tooling, like bundlers and isomorphic routers. Finally, we’ll zoom out from React and look at alternatives like Vue, Solid, Angular, Qwik, and more. We’ll explore signals and fine-grained reactivity in contrast to React’s coarser reactivity model. We’ll also explore React’s response to signals: the Forget toolchain and how it stacks up when compared to signals. There’s so much to get into, so let’s not waste any more time. Let’s get started! Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold and light gray text Used in Chapter 10 of the print edition to highlight diffs in code blocks.
📄 Page
11
NOTE This element signifies a general note. O’Reilly Online Learning NOTE For more than 40 years, O’Reilly Media has provided technology and business training, knowledge, and insight to help companies succeed. Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-889-8969 (in the United States or Canada) 707-827-7019 (international or local)
📄 Page
12
707-829-0104 (fax) support@oreilly.com https://www.oreilly.com/about/contact.html We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/fluent- react. For news and information about our books and courses, visit https://oreilly.com. Find us on LinkedIn: https://linkedin.com/company/oreilly-media Follow us on Twitter: https://twitter.com/oreillymedia Watch us on YouTube: https://youtube.com/oreillymedia Acknowledgments This book is the first book that I’ve ever written, and I am beyond thankful that I did not do it alone. What you’re about to read is the combined effort of a number of brilliant people who have worked in concert to make this possible. On this page, we acknowledge these people for their contributions to this body of text. Please do not skip this, because these people deserve your attention and your gratitude. Let’s start off with the people who have helped me directly with this book: Number one is always my wife, Lea. I’ve spent a lot of time writing this book, often at the cost of together time and family time. Because of my joy in the subject matter and my desire to share it with all of you, working on this book has slightly eaten into vacation time and other opportunities to spend time with my wife. She has been nothing but supportive and encouraging, and I am so thankful for her.
📄 Page
13
Shira Evans, my development editor on this book. Shira from O’Reilly has been a joy to work with and has been nothing short of supportive, encouraging, and understanding, even when we were faced with a number of delays since new things kept coming up with React, like Forget and server actions. Shira patiently saw us through all of it, and I am so thankful for her. My dear friend and brother Kent C. Dodds (@kentcdodds) for his continued mentorship outside the capacities of this book, and for his foreword in this book. Kent has been a dear friend and mentor for years, and I am so thankful for his continued support and encouragement. The reviewers. This book would not be possible without the incredible care and attention to detail by the reviewers who partnered with me on this book: Adam Rackis (@adamrackis) Daniel Afonso (@danieljcafonso) Fabien Bernard (@fabien0102) Kent C. Dodds (@kentcdodds) Mark Erikson (@acemarke) Lenz Weber-Tronic (@phry) Rick Hanlon II (@rickhanlonii) Sergeii Kirianov (@SergiiKirianov) Matheus Albuquerque (@ythecombinator) The React team at Meta for their continued work on React, continuing to push the boundaries of what’s possible with React and making it a joy to use through their brilliance, ingenuity, and engineering acumen. In particular, Dan Abramov (@dan_abramov), who took the time to explain the role of the bundler in the React Server Components
📄 Page
14
architecture, as well as for contributing a significant portion of Chapter 9 on React Server Components. Finally, I’d like to thank you, the reader, for your interest in this book. I hope you find it as rewarding to read as I have found it to write.
📄 Page
15
Chapter 1. The Entry-Level Stuff Let’s start with a disclaimer: React was made to be used by all. In fact, you could go through life having never read this book and continue to use React without problems! This book dives much deeper into React for those of us who are curious about its underlying mechanism, advanced patterns, and best practices. It lends itself better to knowing how React works instead of learning how to use React. There are plenty of other books that are written with the intent to teach folks how to use React as an end user. In contrast, this book will help you understand React at the level of a library or framework author instead of an end user. In keeping with that theme, let’s go on a deep dive together, starting at the top: the higher-level, entry-level topics. We’ll start with the basics of React, and then dive deeper and deeper into the details of how React works. In this chapter, we’ll talk about why React exists, how it works, and what problems it solves. We’ll cover its initial inspiration and design, and follow it from its humble beginnings at Facebook to the prevalent solution that it is today. This chapter is a bit of a meta chapter (no pun intended), because it’s important to understand the context of React before we dive into the details. Why Is React a Thing? The answer in one word is: updates. In the early days of the web, we had a lot of static pages. We’d fill out forms, hit Submit, and load an entirely new page. This was fine for a while, but eventually web experiences evolved significantly in terms of capabilities. As the capabilities grew, so did our desire for superior user experiences on the web. We wanted to be able to see things update instantly without having to wait for a new page to be rendered and loaded. We wanted the web and its pages to feel snappier and more “instant.” The problem was that these instant updates were pretty hard to do at scale for a number of reasons:
📄 Page
16
Performance Making updates to web pages often caused performance bottlenecks because we were prone to perform work that triggered browsers to recalculate a page’s layout (called a reflow) and repaint the page. Reliability Keeping track of state and making sure that the state was consistent across a rich web experience was hard to do because we had to keep track of state in multiple places and make sure that the state was consistent across all of those places. This was especially hard to do when we had multiple people working on the same codebase. Security We had to be sure to sanitize all HTML and JavaScript that we were injecting into the page to prevent exploits like cross-site scripting (XSS) and cross-site request forgery (CSRF). To fully understand and appreciate how React solves these problems for us, we need to understand the context in which React was created and the world without or before React. Let’s do that now. The World Before React These were some of the large problems for those of us building web apps before React. We had to figure out how to make our apps feel snappy and instant, but also scale to millions of users and work reliably in a safe way. For example, let’s consider a button click: when a user clicks a button, we want to update the user interface to reflect that the button has been clicked. We’ll need to consider at least four different states that the user interface can be in: Pre-click The button is in its default state and has not been clicked.
📄 Page
17
Clicked but pending The button has been clicked, but the action that the button is supposed to perform has not yet completed. Clicked and succeeded The button has been clicked, and the action that the button is supposed to perform has completed. From here, we may want to revert the button to its pre-click state, or we may want the button to change color (green) to indicate success. Clicked and failed The button has been clicked, but the action that the button is supposed to perform has failed. From here, we may want to revert the button to its pre-click state, or we may want the button to change color (red) to indicate failure. Once we have these states, we need to figure out how to update the user interface to reflect them. Oftentimes, updating the user interface would require the following steps: 1. Find the button in the host environment (often the browser) using some type of element locator API, such as document.querySelector or document.getElementById. 2. Attach event listeners to the button to listen for click events. 3. Perform any state updates in response to events. 4. When the button leaves the page, remove the event listeners and clean up any state. This is a simple example, but it’s a good one to start with. Let’s say we have a button labeled “Like,” and when a user clicks it, we want to update the button to “Liked.” How do we do this? To start with, we’d have an HTML element:
📄 Page
18
<button>Like</button> We’d need some way to reference this button with JavaScript, so we’d give it an id attribute: <button id="likeButton">Like</button> Great! Now that there’s an id, JavaScript can work with it to make it interactive. We can get a reference to the button using document.getElementById, and then we’ll add an event listener to the button to listen for click events: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { // do something }); Now that we have an event listener, we can do something when the button is clicked. Let’s say we want to update the button to have the label “Liked” when it’s clicked. We can do this by updating the button’s text content: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { likeButton.textContent = "Liked"; }); Great! Now we have a button that says “Like,” and when it’s clicked, it says “Liked.” The problem here is that we can’t “unlike” things. Let’s fix that and update the button to say “Like” again if it’s clicked in its “Liked” state. We’d need to add some state to the button to keep track of whether or not it’s been clicked. We can do this by adding a data-liked attribute to the button: <button id="likeButton" data-liked="false">Like</button> Now that we have this attribute, we can use it to keep track of whether or not the button has been clicked. We can update the button’s text content
📄 Page
19
based on the value of this attribute: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { const liked = likeButton.getAttribute("data-liked") === "true"; likeButton.setAttribute("data-liked", !liked); likeButton.textContent = liked ? "Like" : "Liked"; }); Wait, but we’re just changing the textContent of the button! We’re not actually saving the “Liked” state to a database. Normally, to do this we had to communicate over the network, like so: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { var liked = likeButton.getAttribute("data-liked") === "true"; // communicate over the network var xhr = new XMLHttpRequest(); xhr.open("POST", "/like", true); xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 400) { // Success! likeButton.setAttribute("data-liked", !liked); likeButton.textContent = liked ? "Like" : "Liked"; } else { // We reached our target server, but it returned an error console.error("Server returned an error:", xhr.statusText); } }; xhr.onerror = function () { // There was a connection error of some sort console.error("Network error."); }; xhr.send(JSON.stringify({ liked: !liked })); }); Of course, we’re using XMLHttpRequest and var to be time relevant. React was released as open source software in 2013, and the more common fetch
📄 Page
20
API was introduced in 2015. In between XMLHttpRequest and fetch, we had jQuery that often abstracted away some complexity with primitives like $.ajax(), $.post(), etc. If we were to write this today, it would look more like this: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { const liked = likeButton.getAttribute("data-liked") === "true"; // communicate over the network fetch("/like", { method: "POST", body: JSON.stringify({ liked: !liked }), }).then(() => { likeButton.setAttribute("data-liked", !liked); likeButton.textContent = liked ? "Like" : "Liked"; }); }); Without digressing too much, the point now is that we’re communicating over the network, but what if the network request fails? We’d need to update the button’s text content to reflect the failure. We can do this by adding a data-failed attribute to the button: <button id="likeButton" data-liked="false" data-failed="false">Like</button> Now we can update the button’s text content based on the value of this attribute: const likeButton = document.getElementById("likeButton"); likeButton.addEventListener("click", () => { const liked = likeButton.getAttribute("data-liked") === "true"; // communicate over the network fetch("/like", { method: "POST", body: JSON.stringify({ liked: !liked }), }) .then(() => { likeButton.setAttribute("data-liked", !liked); likeButton.textContent = liked ? "Like" : "Liked";