<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dominik D</title>
    <description>The latest articles on DEV Community by Dominik D (@tkdodo).</description>
    <link>https://dev.to/tkdodo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F536846%2F75347e63-1654-4e06-8dae-69af81429d29.png</url>
      <title>DEV Community: Dominik D</title>
      <link>https://dev.to/tkdodo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tkdodo"/>
    <language>en</language>
    <item>
      <title>Why React isn't dying</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Tue, 31 Jan 2023 13:34:42 +0000</pubDate>
      <link>https://dev.to/tkdodo/why-react-isnt-dying-k42</link>
      <guid>https://dev.to/tkdodo/why-react-isnt-dying-k42</guid>
      <description>&lt;p&gt;Last Thursday, I took part in the &lt;a href="https://www.youtube.com/watch?v=_nGuk2Gs2oc" rel="noopener noreferrer"&gt;State of React Ecosystem&lt;/a&gt; panel discussion, where we mainly talked about one question: "Is React dying" ? I couldn't finish my train of thought due to a StreamYard outage, so I thought I'd follow this up with a blogpost. So, why would React be dying?&lt;/p&gt;

&lt;h2&gt;
  
  
  Twitter bubble
&lt;/h2&gt;

&lt;p&gt;There's a bit of fuzz, mainly on Twitter, about React dying and other libraries being better than React, and that you're doing something wrong or missing out if you're choosing React right now.&lt;/p&gt;

&lt;p&gt;The truth is, my bubble consists of very smart people, library authors, maintainers and tech influencers who love to live on the bleeding edge, where you constantly have to be on the lookout for the next big thing. In that world, you see everything through a different lens - one that is more focussed on the future than the status quo. It is only natural that you see lots of push and innovation in that space. Things are pronounced dead way before they really are, and I think it's no different this time.&lt;/p&gt;

&lt;p&gt;To understand why React is here to stay, we have to look back a bit:&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking back
&lt;/h2&gt;

&lt;p&gt;React has been around for almost 10 years now, and it has pioneered so many things that we now take for granted. This includes the two biggest reasons why I think react has "won" in the first place: &lt;code&gt;Component Driven Development&lt;/code&gt; and &lt;code&gt;JSX&lt;/code&gt; - two things that most new tech now embraces as well.&lt;/p&gt;

&lt;p&gt;Also, React gave us a predictable way to render our UI. Before that, everything we used was a mess (compared to today's standards). We had the choice to either update the DOM manually in an imperative spaghetti mess (jQuery 👀) or wrestle with two-way data binding and a weird templating syntax (👋 angular).&lt;/p&gt;

&lt;p&gt;So React allowed us to abstract our UI into components and couple functionality (JS) with markup (HTML) in a declarative, reusable way. This was revolutionary at the time. When it came out, lots of people jumped ship rather fast (me included), because React was &lt;em&gt;so much better&lt;/em&gt; than the given alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  New horizons
&lt;/h2&gt;

&lt;p&gt;The new kids on the block now try to take the good parts of React and use that to invent something that doesn't have its drawbacks. Things usually cited are performance, virtual dom overhead and a generally hard way to interact with the dom directly, e.g. for animations or a11y (refs 😭).&lt;/p&gt;

&lt;p&gt;However, being up against the top dog React will be very hard, for two reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  Growth loop
&lt;/h3&gt;

&lt;p&gt;Every day, there are so many people just starting out with web development. They look around for what is the best tech to learn right now to get a job. Something that pays the bills and is not terrible to work with. And everything points towards React. Companies have lots of existing React Applications, and are still choosing React for new stuff. It's an easy and safe choice.&lt;/p&gt;

&lt;p&gt;On the other hand, companies choose React because that's where all the developers are. If you want to build something that can be maintained years from now, you better not choose the next hype train that goes straight to nowhere (remember &lt;a href="https://coffeescript.org/" rel="noopener noreferrer"&gt;CoffeeScript&lt;/a&gt; ?). You want something battle tested that has stood the test of time, where you won't have trouble finding developers to scale once you need to. And nobody ever got fired for choosing React.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ayu6hxvdw2kztg2pde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ayu6hxvdw2kztg2pde.png" alt="A closing circle with two arrows: Companies choose React because that's where the devs are; Devs choose React because that's where the jobs are" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecosystem
&lt;/h3&gt;

&lt;p&gt;It can take years to build a good ecosystem and community. Libraries and Frameworks that come out right now won't have everything figured out immediately. It needs early adopters to figure things out, find and teach patterns and invent community solutions to problems. To grow adoption, a vibrant ecosystem is an absolute necessity.&lt;/p&gt;

&lt;p&gt;React is years ahead here. Even &lt;a href="https://marmelab.com/blog/2022/09/20/react-i-love-you.html#i-cant-quit-you-baby" rel="noopener noreferrer"&gt;critical articles&lt;/a&gt; state that they can't quit React because it has the "best community and the best third-party modules".&lt;/p&gt;

&lt;h3&gt;
  
  
  The TanStack
&lt;/h3&gt;

&lt;p&gt;This is where the &lt;a href="https://tanstack.com/" rel="noopener noreferrer"&gt;TanStack&lt;/a&gt; comes in. I really hope that the fact that the TanStack has all packages built in a framework-agnostic way will help adoption of non-React libraries over time. Think about it: If you need to fetch some data, render a table and maybe virtualize it - you can do all of that with the TanStack. And if you know how to do this in React, you also already know how to do it in Solid, Svelte or Vue.&lt;/p&gt;

&lt;p&gt;Knowing the concepts is &lt;em&gt;transferable knowledge&lt;/em&gt;. And it takes away a bunch of things you'd have to re-learn when moving to a different, newer tech, while retaining the same great developer experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;It's true that there are already solutions out there that are "better than React" in some aspects. More modern, more performant, different paradigms, "really reactive", ...&lt;/p&gt;

&lt;p&gt;But to break the growth loop, to get a lot of developers to move over, to build a large community and ecosystem, I think it will need something that's &lt;em&gt;a lot&lt;/em&gt; better than React to replace it. Just like React was so much better than the alternatives when it came out.&lt;/p&gt;

&lt;p&gt;And we aren't there yet. React is still "good enough" for most things that are built right now, and I don't see that changing in the near future. That doesn't mean finding new tech isn't worth trying. We need innovation. It might happen in React, or it might happen outside of it. Only time will tell.&lt;/p&gt;

&lt;p&gt;Actually, both might happen. It's not a given that you have one tech ruling them all. A monopoly is also not something to strive for. Competition helps everyone, especially users. We can already see how the rise of fine-grained reactivity influences existing libs like &lt;a href="https://preactjs.com/guide/v10/signals/" rel="noopener noreferrer"&gt;Preact&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1465702417513680897-962" src="https://platform.twitter.com/embed/Tweet.html?id=1465702417513680897"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1465702417513680897-962');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1465702417513680897&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;It's exciting times for sure - but don't feel that you have to stay on top of the bleeding edge, that you have to learn everything the moment it comes out or that React isn't good enough.&lt;/p&gt;

&lt;p&gt;Because it's not dying.&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>welcome</category>
    </item>
    <item>
      <title>Seeding the Query Cache</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Sun, 11 Dec 2022 18:50:38 +0000</pubDate>
      <link>https://dev.to/tkdodo/seeding-the-query-cache-5g6g</link>
      <guid>https://dev.to/tkdodo/seeding-the-query-cache-5g6g</guid>
      <description>&lt;p&gt;A new RFC about &lt;a href="https://github.com/reactjs/rfcs/pull/229"&gt;first class support for Promises&lt;/a&gt; has been released last week, and it got some talk going about how this would introduce fetch waterfalls if used incorrectly. So what are fetch waterfalls exactly?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetch waterfalls
&lt;/h2&gt;

&lt;p&gt;A waterfall describes a situation where one request is made, and we wait for it to complete before firing another request.&lt;/p&gt;

&lt;p&gt;Sometimes, this is unavoidable, because the first request contains information that is needed to make the second request. We also refer to these as &lt;a href="https://tanstack.com/query/v4/docs/guides/dependent-queries"&gt;dependent queries&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nPmZsUc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wv59it0sauc0vfdg3v6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nPmZsUc6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wv59it0sauc0vfdg3v6o.png" alt="component mounts, /user endpoint is being fetched, and after that, we fire off two requests for the user's projects and todos" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In many cases though, we can actually fetch all the data we need in parallel, because it is independent data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---elcn97A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydum9l65dva0usqyyzoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---elcn97A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydum9l65dva0usqyyzoy.png" alt="component mounts, both /issues and /labels are fetched at the same time" width="880" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In React Query, we can do that in two different ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Use useQuery twice&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIssues&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;labels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchLabels&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Use the useQueries hook&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQueries&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIssues&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;labels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchLabels&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both variants, React Query will kick off data fetching in parallel. So where do waterfalls come in?&lt;/p&gt;

&lt;h3&gt;
  
  
  Suspense
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Please keep in mind that at the time of this writing, suspense for data fetching is still experimental! In the following examples, I will not be using the proposal from the RFC, but rather the suspense implementation that is already available in React Query (which is also experimental).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As described in the above linked RFC, suspense a way to unwrap promises with React. A defining trait of promises is that they can be in three different states: pending, fulfilled or rejected.&lt;/p&gt;

&lt;p&gt;When rendering components, we are mostly interested in the success scenario. Handling loading and error states in each and every component can be tedious, and suspense is aimed at solving this problem.&lt;/p&gt;

&lt;p&gt;When a promise is &lt;em&gt;pending&lt;/em&gt;, React will unmount the component tree and render a fallback defined by a &lt;em&gt;Suspense&lt;/em&gt; boundary component. In case of errors, the error is bubbled up to the nearest &lt;em&gt;ErrorBoundary&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This will decouple our components from handling those states, and we can focus on the happy path. It almost acts like synchronous code that just &lt;em&gt;reads&lt;/em&gt; a value from a cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Issues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 👓 read data from cache&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIssues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ⬇️ this enables experimental suspense mode&lt;/span&gt;
    &lt;span class="na"&gt;suspense&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// 🎉 no need to handle loading or error states&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 🚀 Boundaries handle loading and error states&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;On no!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Issues&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  A note on TypeScript
&lt;/h4&gt;

&lt;p&gt;Sadly, when using TypeScript, data will still be potentially &lt;em&gt;undefined&lt;/em&gt; in the above example, as &lt;em&gt;suspense&lt;/em&gt; is just a flag on &lt;em&gt;useQuery&lt;/em&gt; that can be turned on and off at will. It can also be combined with the &lt;em&gt;enabled&lt;/em&gt; option, which will make the query not fire and thus make the component &lt;em&gt;not&lt;/em&gt; suspend at all.&lt;/p&gt;

&lt;p&gt;We might change this in the future with a dedicated &lt;em&gt;useSuspenseQuery&lt;/em&gt; hook.&lt;/p&gt;

&lt;h3&gt;
  
  
  Suspense waterfalls
&lt;/h3&gt;

&lt;p&gt;So this is nice and all, but it can backfire when you use multiple queries in the same component that have suspense turned on. Here is what happens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xohrkncq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9zeofrws74hsof06psfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xohrkncq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9zeofrws74hsof06psfi.png" alt="component mounts, /issues are fetched and component suspends. After the request is finished, component mounts and suspends again, triggering a fetch for /labels" width="880" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component renders, tries to read the first query&lt;/li&gt;
&lt;li&gt;Sees that there is no data in the cache yet, so it suspends&lt;/li&gt;
&lt;li&gt;This unmounts the component tree, and renders the fallback&lt;/li&gt;
&lt;li&gt;When the fetch is finished, the component tree is remounted&lt;/li&gt;
&lt;li&gt;First query is now read successfully from the cache&lt;/li&gt;
&lt;li&gt;Component sees the second query, and tries to read it&lt;/li&gt;
&lt;li&gt;Second query has no data in the cache, so it suspends (again)&lt;/li&gt;
&lt;li&gt;Second query is fetched&lt;/li&gt;
&lt;li&gt;Component finally renders successfully&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will have pretty impactful implications on your application's performance, because you'll see that fallback for waaay longer than necessary.&lt;/p&gt;

&lt;p&gt;The best way to circumvent this problem is to make sure that there is already data in the cache when the component tries to read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefetching
&lt;/h2&gt;

&lt;p&gt;The earlier you initiate a fetch, the better, because the sooner it starts, the sooner it can finish. 🤓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your architecture supports server side rendering - consider &lt;a href="https://tanstack.com/query/v4/docs/guides/ssr"&gt;fetching on the server&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you have a router that supports loaders, consider &lt;a href="https://tanstack.com/query/v4/docs/guides/ssr"&gt;prefetching there&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even if that's not the case, you can still use &lt;em&gt;prefetchQuery&lt;/em&gt; to initiate a fetch before the component is rendered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issuesQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchIssues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ⬇️ initiate a fetch before the component renders&lt;/span&gt;
&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefetchQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issuesQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Issues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issuesQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The call to &lt;em&gt;prefetchQueries&lt;/em&gt; is executed as soon as your JavaScript bundle is evaluated. This works very well if you do &lt;a href="https://reactjs.org/docs/code-splitting.html#route-based-code-splitting"&gt;route base code splitting&lt;/a&gt;, because it means the code for a certain page will be lazily loaded and evaluated as soon as the user navigates to that page.&lt;/p&gt;

&lt;p&gt;This means it will still be kicked off before the component renders. If you do this for both queries in our example, you will get those parallel queries back even when using suspense.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I8cs-bmL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eelw9iyshsqapqijlb1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I8cs-bmL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eelw9iyshsqapqijlb1e.png" alt="prefetch for both queries triggers before the component mounts. component suspends for a short time until both queries re finished." width="880" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, the query will still suspend until both are done fetching, but because we've triggered them in parallel, the waiting time is now drastically reduced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;em&gt;useQueries&lt;/em&gt; doesn't support &lt;em&gt;suspense&lt;/em&gt; right now, but it might do in the future. If we add support, the goal is to trigger all fetches in parallel to avoid those waterfalls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;em&gt;useQueries&lt;/em&gt; supports &lt;em&gt;suspense&lt;/em&gt; as of &lt;a href="https://github.com/TanStack/query/releases/tag/v4.15.0"&gt;v4.15.0&lt;/a&gt;. 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  The use RFC
&lt;/h3&gt;

&lt;p&gt;I don't know enough about the RFC yet to properly comment on it. A big part is still missing, namely how the cache API will work. I do think it is a bit problematic that the default behaviour will lead to waterfalls unless developers explicitly seed the cache early on. I'm still pretty excited about it because it will likely make internals of React Query easier to understand and maintain. It remains to be seen if it is something that will be used in userland a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeding details from lists
&lt;/h2&gt;

&lt;p&gt;Another nice way to make sure that your cache is filled by the time it is read is to seed it from other parts of the cache. Oftentimes, if you render a detail view of an item, you will have data for that item readily available if you've previously been on a list view that shows a list of items.&lt;/p&gt;

&lt;p&gt;There are two common approaches to fill a detail cache with data from a list cache:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull approach
&lt;/h3&gt;

&lt;p&gt;This is the one also described &lt;a href="https://tanstack.com/query/v4/docs/guides/initial-query-data#initial-data-from-cache"&gt;in the docs&lt;/a&gt;: When you try to render the detail view, you look up the list cache for the item you want to render. If it is there, you use it as initial data for the detail query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQueryClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ⬇️ look up the list cache for the item&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getQueryData&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;em&gt;initialData&lt;/em&gt; function returns &lt;em&gt;undefined&lt;/em&gt;, the query will proceed as normal and fetch the data from the server. And if something is found, it will be put into the cache directly.&lt;/p&gt;

&lt;p&gt;Be advised that if you have &lt;em&gt;staleTime&lt;/em&gt; set, no further background refetch will occur, as initialData is seen as &lt;em&gt;fresh&lt;/em&gt;. This might not be what you want if your list was last fetched twenty minutes ago.&lt;/p&gt;

&lt;p&gt;As shown &lt;a href="https://tanstack.com/query/v4/docs/guides/initial-query-data#initial-data-from-the-cache-with-initialdataupdatedat"&gt;in the docs&lt;/a&gt;, we can additionally specify &lt;em&gt;initialDataUpdatedAt&lt;/em&gt; on our detail query. It will tell React Query when the data we are passing in as &lt;em&gt;initialData&lt;/em&gt; was originally fetched, so it can determine staleness correctly. Conveniently, React Query also knows when the list was last fetched, so we can just pass that in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQueryClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getQueryData&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;initialDataUpdatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// ⬇️ get the last fetch time of the list&lt;/span&gt;
      &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getQueryState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])?.&lt;/span&gt;&lt;span class="nx"&gt;dataUpdatedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🟢 seeds the cache "just in time"&lt;br&gt;
🔴 needs more work to account for staleness&lt;/p&gt;
&lt;h3&gt;
  
  
  Push approach
&lt;/h3&gt;

&lt;p&gt;Alternatively, you can create detail caches whenever you fetch the list query. This has the advantage that staleness is automatically measured from when the list was fetched, because, well, that's when we create the detail entry.&lt;/p&gt;

&lt;p&gt;However, there is no good callback to hook into when a query is fetched. &lt;em&gt;onSuccess&lt;/em&gt; on &lt;em&gt;useQuery&lt;/em&gt; would technically work, but it would be executed for every instance of &lt;em&gt;useQuery&lt;/em&gt;. If we have multiple observers, this would lead to the same data being written to the cache multiple times. The global &lt;em&gt;onSuccess&lt;/em&gt; callback on the cache itself might also work, but it would be executed for every query, so we'd have to narrow it down to the right query key.&lt;/p&gt;

&lt;p&gt;The best way I've found to execute the push approach is to do it directly in the &lt;em&gt;queryFn&lt;/em&gt;, after data has been fetched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQueryClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ⬇️ create a detail cache for each item&lt;/span&gt;
        &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setQueryData&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would create a detail entry for each item in the list immediately. Since there is no one interested in those queries at the moment, those would be seen as &lt;em&gt;inactive&lt;/em&gt;, which means they might be garbage collected after &lt;em&gt;cacheTime&lt;/em&gt; has elapsed (default: 15 minutes).&lt;/p&gt;

&lt;p&gt;So if you use the push approach, the detail entries you've created here might no longer be available once the user actually navigates to the detail view. Also, if your list is long, you might be creating way too many entries that will never be needed.&lt;/p&gt;

&lt;p&gt;🟢 staleTime is automatically respected&lt;br&gt;
🟡 there is no good callback&lt;br&gt;
🟡 might create unnecessary cache entries&lt;br&gt;
🔴 pushed data might be garbage collected too early&lt;/p&gt;




&lt;p&gt;Keep in mind that both approaches only work well if the structure of your detail query is exactly the same (or at least assignable to) the structure of the list query. If the detail view has a mandatory field that doesn't exist in the list, seeding via &lt;em&gt;initialData&lt;/em&gt; is not a good idea. This is where &lt;em&gt;placeholderData&lt;/em&gt; comes in, and I've written a comparison about the two in &lt;a href="https://tkdodo.eu/blog/placeholder-and-initial-data-in-react-query"&gt;#9: Placeholder and Initial Data in React Query&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Refs, Events and Escape Hatches</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Fri, 30 Sep 2022 20:05:36 +0000</pubDate>
      <link>https://dev.to/tkdodo/refs-events-and-escape-hatches-59j6</link>
      <guid>https://dev.to/tkdodo/refs-events-and-escape-hatches-59j6</guid>
      <description>&lt;p&gt;I hope that after reading part one about &lt;a href="https://tkdodo.eu/blog/hooks-dependencies-and-stale-closures" rel="noopener noreferrer"&gt;stale closures in React&lt;/a&gt;, you now have a good understanding of why they can occur and how to avoid them.&lt;/p&gt;

&lt;p&gt;However, it is sometimes quite cumbersome to have to think about referential stability when passing functions around, and it can also get a bit boilerplate-y with all those additional &lt;em&gt;useCallbacks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I already left a bunch of clues in the previous article that there might be a way to make this easier, so here we go:&lt;/p&gt;

&lt;h2&gt;
  
  
  Photoshop
&lt;/h2&gt;

&lt;p&gt;Remember this sentence?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The thing about the picture is - it cannot change. Once we have taken it, its content is sealed (unless we use photoshop).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In React, we almost always think in immutability. &lt;em&gt;Props&lt;/em&gt; cannot be changed (from within a component), and &lt;em&gt;state&lt;/em&gt; updates are merely scheduled and also need to happen in an immutable way. Everything we see and work with is essentially a &lt;em&gt;const&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We always see the things from the time they were created, but if they are &lt;em&gt;mutated&lt;/em&gt; in place, we would still see the latest value. Let's take the basic example from part 1 and store the value in a mutable variable outside the React component:(note: examples are interactive on my blog: &lt;a href="https://tkdodo.eu/blog/refs-events-and-escape-hatches" rel="noopener noreferrer"&gt;https://tkdodo.eu/blog/refs-events-and-escape-hatches&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rerender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({}))[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;// 😱 logCount is stable, but it still sees&lt;/span&gt;
  &lt;span class="c1"&gt;// the latest value of count&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
          &lt;span class="nf"&gt;rerender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;increment&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's hopefully obvious that this is &lt;em&gt;not&lt;/em&gt; how you would work with React. Having a variable outside the component means it's shared between component instances, and React doesn't know about it, which is why we have to manually force our component to re-render.&lt;/p&gt;

&lt;p&gt;But it showcases one thing: &lt;em&gt;mutating&lt;/em&gt; a variable in place bypasses our mental modal of pictures that cannot change.&lt;/p&gt;

&lt;p&gt;Mutations are literally photoshop. They can alter existing images after they have been taken. And what's the React way to hold mutable values? &lt;a href="https://beta.reactjs.org/learn/escape-hatches#referencing-values-with-refs" rel="noopener noreferrer"&gt;Refs&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Refs
&lt;/h2&gt;

&lt;p&gt;Refs are just bags that can contain an arbitrary mutable value. The ref itself is referentially stable, so we don't have to include it in dependency arrays, and the &lt;em&gt;.current&lt;/em&gt; property has the actual value. Refs offer an escape hatch from Reacts one way data flow model, because updates on refs are not going to make your component to re-render. This comes in quite handy if we have to pass functions around, e.g. to custom hooks.&lt;/p&gt;

&lt;p&gt;As an example, let's implement a somewhat common use-case of storing a value and triggering a callback after some debounced time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDebouncedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've added &lt;em&gt;callback&lt;/em&gt; to the effect's dependency array as the linter wants, but that has a downside: consumers will need to memoize the function, which is not a very developer friendly interface. Of course, they'll most often just want to use an inline function, without having to care about referential stability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDebouncedState&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will potentially run our effect too often, e.g. if the component re-renders for another reason. However, omitting the function from the dependency array is not an option, as it would potentially introduce stale closures.&lt;/p&gt;

&lt;h3&gt;
  
  
  The latest ref
&lt;/h3&gt;

&lt;p&gt;I first read about a pattern called &lt;em&gt;the latest ref&lt;/em&gt; in &lt;a href="https://epicreact.dev/the-latest-ref-pattern-in-react/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; by &lt;a href="https://twitter.com/kentcdodds" rel="noopener noreferrer"&gt;Kent C. Dodds&lt;/a&gt;. The idea is to store the function (our callback) in a ref so that we can omit it from the dependency array. All we then need to do is to make sure that the ref is updated when the function changes, and we can do that with an additional effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDebouncedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// 👇 store callback in a ref&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 👇 update the ref when the callback changes&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 👇 use the ref instead of the callback&lt;/span&gt;
        &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// 👇 no need to include the callback&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Admittedly, this does add more boilerplate, but it pays off - especially for libraries or reusable hooks due to the improved developer experience for consumers of the hook. Also, hold on tight because React might actually ship a hook that does this for us in the future:&lt;/p&gt;

&lt;h2&gt;
  
  
  useEvent
&lt;/h2&gt;

&lt;p&gt;Recently, the React team has worked on an RFC about a dedicated hook for this behaviour called &lt;a href="https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md" rel="noopener noreferrer"&gt;useEvent&lt;/a&gt;. The idea is to have a hook that is similar to &lt;em&gt;useCallback&lt;/em&gt;, except that it doesn't have a dependency array, but still returns a stable function reference without suffering from stale closure problems.&lt;/p&gt;

&lt;p&gt;As pointed out in the &lt;a href="https://beta.reactjs.org/learn/separating-events-from-effects#declaring-an-event-function" rel="noopener noreferrer"&gt;new beta docs&lt;/a&gt;, those event functions behave a lot more like an event handler (hence the name). The logic inside it is not reactive, and it always sees the latest values of your props and state.&lt;/p&gt;

&lt;p&gt;Would that hook exist already, we could rewrite our &lt;em&gt;useDebouncedState&lt;/em&gt; hook like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDebouncedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 👇 declare the event&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 👇 use the event&lt;/span&gt;
        &lt;span class="nf"&gt;onTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// 🎉 no need to include onTimeout&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks pretty clean to me, and if you want to have a user-land implementation of &lt;em&gt;useEvent&lt;/em&gt; right now, have a look at this implementation by &lt;a href="https://twitter.com/diegohaz" rel="noopener noreferrer"&gt;Diego Haz&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1522868292301606912-245" src="https://platform.twitter.com/embed/Tweet.html?id=1522868292301606912"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1522868292301606912-245');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1522868292301606912&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;You can use it until React ships their own hook, but be aware that you have to include the returned function in the dependency array because unlike the native implementation, the linter cannot know that the function is stable. I personally can't wait until this ships because it will simplify a lot of my code. 🙌&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React Query meets React Router</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Mon, 12 Sep 2022 19:18:45 +0000</pubDate>
      <link>https://dev.to/tkdodo/react-query-meets-react-router-38f3</link>
      <guid>https://dev.to/tkdodo/react-query-meets-react-router-38f3</guid>
      <description>&lt;p&gt;&lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt; is changing the game, and they are bringing their data fetching concepts (loaders and actions) to purely client side rendered applications with &lt;a href="https://beta.reactrouter.com/en/dev" rel="noopener noreferrer"&gt;React Router 6.4&lt;/a&gt;. At the time of this writing, v6.4 is still in beta, but I went through their great &lt;a href="https://beta.reactrouter.com/en/dev/getting-started/tutorial" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; that shows the concept very well and demonstrates how you can quickly build a small, but feature-rich app.&lt;/p&gt;

&lt;p&gt;With React Router coming into the data fetching game, it is naturally interesting to understand how this competes or correlates with existing data fetching and caching libraries like React Query. So let me spoil it right here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They are a match made in heaven&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A router that fetches data
&lt;/h2&gt;

&lt;p&gt;To recap: React Router will allow you to define &lt;a href="https://beta.reactrouter.com/en/dev/route/loader" rel="noopener noreferrer"&gt;loaders&lt;/a&gt; on each route, which will be called when the route is visited. In the route component itself, you can &lt;code&gt;useLoaderData()&lt;/code&gt; to get access to that data. Updating data is as simple as submitting a &lt;em&gt;Form&lt;/em&gt;, which will call an &lt;a href="https://beta.reactrouter.com/en/dev/route/action" rel="noopener noreferrer"&gt;action&lt;/a&gt; function. Actions invalidate all active loaders, so you'll automagically see updated data on your screen.&lt;/p&gt;

&lt;p&gt;If this sounds very similar to &lt;em&gt;queries&lt;/em&gt; and &lt;em&gt;mutations&lt;/em&gt; - you are right, it does. So the questions that have been popping up after the announcement of &lt;a href="https://remix.run/blog/remixing-react-router" rel="noopener noreferrer"&gt;Remixing React Router&lt;/a&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Would we still want React Query now that we can fetch in the route?&lt;/li&gt;
&lt;li&gt;If we already use React Query, do we want to (and how can we) leverage the new React Router features?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  It's not a cache
&lt;/h3&gt;

&lt;p&gt;To me, the answers to both questions are clearly: YES. As &lt;a href="https://twitter.com/ryanflorence" rel="noopener noreferrer"&gt;Ryan Florence&lt;/a&gt; from the remix team has put it: "React Router is not a cache":&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1561731634419773447-173" src="https://platform.twitter.com/embed/Tweet.html?id=1561731634419773447"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1561731634419773447-173');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1561731634419773447&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;Fetching "as early as possible" is an important concept to provide the best possible user experience. Full Stack frameworks like &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJs&lt;/a&gt; or Remix move this step to the server, because that is the earliest entry point. With client rendered applications, we have no such luxury.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fetching early
&lt;/h3&gt;

&lt;p&gt;What we are usually doing is fetching on component mount - when data is first needed. That is not great, as it will lead to a loading spinner visible to the user for as long as we are initially fetching. &lt;a href="https://tanstack.com/query/v4/docs/guides/prefetching" rel="noopener noreferrer"&gt;Prefetching&lt;/a&gt; can help, but only for subsequent navigations, and you need to manually set it up for every way to navigate to a route.&lt;/p&gt;

&lt;p&gt;The router however is the first component that always knows which page you are trying to visit, and because it now has loaders, it can know which data those pages need to render. This is great for the first page visit - but loaders are called on &lt;em&gt;every&lt;/em&gt; page visit. And as the router has no cache, it will hit the server again, unless we do something about it.&lt;/p&gt;

&lt;p&gt;As an example (yes, this is from the tutorial mentioned before. Credits go to Ryan Florence), suppose you have a list of contacts. If you click on one of them, you show the contact details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../contacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ⬇️ this is the loader for the detail route&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ⬇️ this gives you data from the loader&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// render some jsx&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;contactLoader&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes/contact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Root&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contacts/:contactId"&lt;/span&gt;
        &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// ⬇️ pass the loader to the route&lt;/span&gt;
        &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contactLoader&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you navigate to &lt;code&gt;contacts/1&lt;/code&gt;, data for that contact will be fetched &lt;em&gt;before&lt;/em&gt; the component is rendered. By the time we want to show the Contact, &lt;em&gt;useLoaderData&lt;/em&gt; will have data readily available. This is awesome as it not only improves the user experience, but look at that developer experience of co-located data fetching and rendering! I love it. 🥰&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetching too often
&lt;/h3&gt;

&lt;p&gt;The big drawback of not having a cache shows when you go to Contact 2 and then back to Contact 1 again. If you are used to React Query, you will know that data for Contact 1 is cached already, so we can show it instantly and kick of a background refetch if data is considered stale. With the loader approach, we will have to fetch that data again (and wait for it to finish fetching!), even though we have already fetched it before.&lt;/p&gt;

&lt;p&gt;And that is exactly where React Query comes in.&lt;/p&gt;

&lt;p&gt;What if we can use the loader to pre-fill the React Query Cache, but still &lt;em&gt;useQuery&lt;/em&gt; in the component to get all the React Query goodies like &lt;em&gt;refetchOnWindowFocus&lt;/em&gt; and showing stale data instantly? To me, this sounds like the best of both worlds. The router is responsible for fetching data early (if we don't have it), and React Query is responsible for caching and keeping the data fresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Querifying the example
&lt;/h2&gt;

&lt;p&gt;Let's try to move the example in that direction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../contacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ⬇️ define your query&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contactDetailQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// ⬇️ needs access to queryClient&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;contactDetailQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ⬇️ return data or fetch it&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getQueryData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// ⬇️ useQuery as per usual&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;contactDetailQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="c1"&gt;// render some jsx&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;QueryClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;QueryClientProvider&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Root&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contacts/:contactId"&lt;/span&gt;
          &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="c1"&gt;// ⬇️ pass the queryClient to the route&lt;/span&gt;
          &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;contactLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DataBrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;QueryClientProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a couple of things going on here, so let's break it down:&lt;/p&gt;

&lt;h3&gt;
  
  
  The loader needs access to the QueryClient.
&lt;/h3&gt;

&lt;p&gt;The loader is not a hook, so we can't &lt;em&gt;useQueryClient&lt;/em&gt;. Importing the QueryClient directly is something that &lt;a href="https://tkdodo.eu/blog/react-query-fa-qs#why-should-i-usequeryclient" rel="noopener noreferrer"&gt;I'm not recommending&lt;/a&gt;, so passing it explicitly seems like the best alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;getQueryData&lt;/em&gt; ?? &lt;em&gt;fetchQuery&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;We want the loader to wait for our data to be ready and return it to get a good experience on the first loads. We also want errors to be thrown to the &lt;a href="https://beta.reactrouter.com/en/dev/route/error-element" rel="noopener noreferrer"&gt;errorElement&lt;/a&gt;, so &lt;em&gt;fetchQuery&lt;/em&gt; is the best option. Note that &lt;em&gt;prefetchQuery&lt;/em&gt; doesn't return anything and catches errors internally (otherwise, they are equivalent).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;getQueryData&lt;/em&gt; does the trick for returning any data we have in the cache, even if it's stale. This ensures that recurring visits to a page will show data immediately. Only if &lt;em&gt;getQueryData&lt;/em&gt; returns &lt;em&gt;undefined&lt;/em&gt; (meaning nothing is in the cache), we'll actually do the fetch.&lt;/p&gt;

&lt;p&gt;An alternative approach would be to set a &lt;em&gt;staleTime&lt;/em&gt; for &lt;em&gt;fetchQuery&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;contactDetailQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting the &lt;em&gt;staleTime&lt;/em&gt; to two minutes tells &lt;em&gt;fetchQuery&lt;/em&gt; to resolve data immediately if it's available and not older than two minutes, otherwise, it will go and fetch it. If you are fine with stale data &lt;em&gt;not&lt;/em&gt; being shown in the component, this is a good alternative.&lt;/p&gt;

&lt;p&gt;Setting &lt;em&gt;staleTime&lt;/em&gt; to &lt;em&gt;Infinity&lt;/em&gt; is almost equivalent to the &lt;em&gt;getQueryData&lt;/em&gt; approach, except that manual query invalidation takes precedence over &lt;em&gt;staleTime&lt;/em&gt;. So I like the &lt;em&gt;getQueryData&lt;/em&gt; approach a bit better, even if it is slightly more code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A TypeScript tip
&lt;/h3&gt;

&lt;p&gt;With this, it is guaranteed that calling &lt;em&gt;useQuery&lt;/em&gt; in the component will have some data available, just like calling &lt;em&gt;useLoaderData&lt;/em&gt; would. However, TypeScript has no way of knowing this - the data returned is of type &lt;code&gt;Contact | undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/mattpocockuk" rel="noopener noreferrer"&gt;Matt Pocock&lt;/a&gt; and his &lt;a href="https://github.com/TanStack/query/pull/3834" rel="noopener noreferrer"&gt;contribution&lt;/a&gt; to React Query v4, we can now exclude &lt;em&gt;undefined&lt;/em&gt; from the union if &lt;em&gt;initialData&lt;/em&gt; is provided.&lt;/p&gt;

&lt;p&gt;And where would we get &lt;em&gt;initialData&lt;/em&gt; from? &lt;em&gt;useLoaderData&lt;/em&gt; of course! We can even infer the type from the loader function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;contactDetailQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// render some jsx&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a bit much to write because our loader is a function that returns a function, but we can tuck that away in a single util. Also, it seems that right now, using type assertions is the only way to narrow the return type of &lt;em&gt;useLoaderData&lt;/em&gt;. 🤷‍♂️&lt;br&gt;
But it will nicely narrow the type of the &lt;em&gt;useQuery&lt;/em&gt; result, which is what we want. 🙌&lt;/p&gt;
&lt;h2&gt;
  
  
  Invalidating in actions
&lt;/h2&gt;

&lt;p&gt;The next piece of the puzzle involves query invalidation. Here is how an action would look without React Query, straight from the tutorial (yes, this is all it takes to perform an update):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actions invalidate loaders, but because we've setup our loaders to always return data from the cache, we won't see any updates unless we somehow invalidate the cache. It's just one line of code really:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invalidateQueries&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://tanstack.com/query/v4/docs/guides/query-invalidation#query-matching-with-invalidatequeries" rel="noopener noreferrer"&gt;fuzzy matching of invalidateQueries&lt;/a&gt; will make sure that our list and our detail view will get new data in the cache by the time the action is finished and we're redirecting back to the detail view.&lt;/p&gt;

&lt;h3&gt;
  
  
  await is the lever
&lt;/h3&gt;

&lt;p&gt;However, this will make our action function take longer and block the transition. Would we not be able to trigger the invalidation, then redirect to the detail view, show the stale data and then let it update in the background once the new data is available? Of course we can: Just leave out the &lt;em&gt;await&lt;/em&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ⬇️ no await here&lt;/span&gt;
    &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invalidateQueries&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Await literally becomes a lever you can pull in either direction (This analogy is based on Ryan's great talk &lt;a href="https://www.youtube.com/watch?v=95B8mnhzoCM" rel="noopener noreferrer"&gt;When To Fetch&lt;/a&gt;. Please watch it if you haven't already):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it important to transition back to the detail view as soon as possible? Do not await.&lt;/li&gt;
&lt;li&gt;Is it important to avoid potential layout shifts when showing stale data, or do you want to keep the action pending until you have all new data? Use await.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If multiple invalidations are involved, you can also mix and match the two approaches to wait for important refetches, but let less important ones be done in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I'm very excited about the new React Router release. It's a great step forward to enable all applications to trigger fetches as early as possible. However, it is not a replacement for caching - so go ahead and combine React Router with React Query to get the best of both worlds. 🚀&lt;/p&gt;

&lt;p&gt;If you want to explore this topic some more, I've implemented the app from the tutorial and added React Query on top of it - you can find it in &lt;a href="https://tanstack.com/query/v4/docs/examples/react/react-router" rel="noopener noreferrer"&gt;the examples of the official docs&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Avoiding useEffect with callback refs</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Sun, 14 Aug 2022 19:10:53 +0000</pubDate>
      <link>https://dev.to/tkdodo/avoiding-useeffect-with-callback-refs-2462</link>
      <guid>https://dev.to/tkdodo/avoiding-useeffect-with-callback-refs-2462</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note: This article assumes a basic understanding of what &lt;em&gt;refs&lt;/em&gt; are in React.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though refs are mutable containers where we can theoretically store arbitrary values, they are most often used to get access to a DOM node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ref&lt;/code&gt; is a reserved property on build-in primitives, where React will store the DOM node after it was rendered. It will be set back to &lt;em&gt;null&lt;/em&gt; when the component is unmounted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with refs
&lt;/h2&gt;

&lt;p&gt;For most interactions, you don't need to access the underlying DOM node, because React will handle updates for us automatically. A good example where you might need a ref is focus management.&lt;/p&gt;

&lt;p&gt;There's a &lt;a href="https://github.com/devongovett/rfcs-1/blob/patch-1/text/2019-focus-management.md"&gt;good RFC&lt;/a&gt; from &lt;a href="https://twitter.com/devongovett"&gt;Devon Govett&lt;/a&gt; that proposes adding FocusManagement to react-dom, but right now, there is nothing in React that will help us with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Focus with an effect
&lt;/h3&gt;

&lt;p&gt;So how would you, right now, focus an input element after it rendered? (I know &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus"&gt;autofocus&lt;/a&gt; exists, this is an example. If this bothers you, imagine you'd want to animate the node instead.)&lt;/p&gt;

&lt;p&gt;Well, most code I've seen tries to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is mostly fine and doesn't violate any rules. The empty dependency array is okay because the only thing used inside is the ref, which is stable. The linter won't complain about adding it to the dependency array, and the ref is also not read during render (which might be troublesome with concurrent react features).&lt;/p&gt;

&lt;p&gt;The effect will run once "on mount" (&lt;a href="https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state"&gt;twice in strict mode&lt;/a&gt;). By that time, React has already populated the ref with the DOM node, so we can focus it.&lt;/p&gt;

&lt;p&gt;Yet this is &lt;em&gt;not&lt;/em&gt; the best way to do it and does have some caveats in some more advanced situations.&lt;/p&gt;

&lt;p&gt;Specifically, it assumes that the ref is "filled" when the effect runs. If it's not available, e.g. because you pass the ref to a custom component which will defer the rendering or only show the input after some other user interaction, the content of the ref will still be &lt;em&gt;null&lt;/em&gt; when the effect runs and nothing will be focussed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 🚨 ref.current is always null when this runs&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setShow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        show
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      // 🧐 ref is attached to the input, but it's conditionally rendered
      // so it won't be filled when the above effect runs
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Form&lt;/em&gt; renders.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;input&lt;/em&gt; is not rendered, &lt;em&gt;ref&lt;/em&gt; is still &lt;em&gt;null&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;effect runs, does nothing.&lt;/li&gt;
&lt;li&gt;input is shown, &lt;em&gt;ref&lt;/em&gt; will be filled, but will not be focussed because effect won't run again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem is that the effect is "bound" to the render function of the Form, while we actually want to express: "Focus the input when the input is rendered", not "when the form mounts".&lt;/p&gt;

&lt;h2&gt;
  
  
  Callback refs
&lt;/h2&gt;

&lt;p&gt;This is where callback refs come into play. If you've ever looked at the &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/fc9b16957473f81a1d708e6948b8d61e292aeb58/types/react/v17/index.d.ts#L85"&gt;type declarations for refs&lt;/a&gt;, we can see that we can not only pass a ref object into it, but also a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RefCallback&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, I like to think about refs on react elements as functions that are called after the component has rendered. This function gets the rendered DOM node passed as argument. If the react element unmounts, it will be called once more with &lt;em&gt;null&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Passing a ref from &lt;em&gt;useRef&lt;/em&gt; (a RefObject) to a react element is therefore just syntactic sugar for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me emphasize this once more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All ref props are just functions!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And those functions run after rendering, where it is totally fine to execute side effects. Maybe it would have been better if &lt;em&gt;ref&lt;/em&gt; would just be called &lt;em&gt;onAfterRender&lt;/em&gt; or something.&lt;/p&gt;

&lt;p&gt;With that knowledge, what stops us from focussing the input right inside the callback ref, where we have direct access to the node?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
  &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, a tiny detail does: React will run this function after &lt;em&gt;every&lt;/em&gt; render. So unless we are fine with focussing our input that often (which we are likely not), we have to tell React to only run this when we want to.&lt;/p&gt;

&lt;h3&gt;
  
  
  useCallback to the rescue
&lt;/h3&gt;

&lt;p&gt;Luckily, React uses referential stability to check if the callback ref should be run or not. That means if we pass the same ref(erence, pun intended) to it, execution will be skipped.&lt;/p&gt;

&lt;p&gt;And that is where &lt;em&gt;useCallback&lt;/em&gt; comes in, because that is how we ensure a function is not needlessly created. Maybe that's why they are called callback-refs - because you have to wrap them in &lt;em&gt;useCallback&lt;/em&gt; all the time. 😂&lt;/p&gt;

&lt;p&gt;Here's the final solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello world"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comparing this to the initial version, it's less code and only uses one hook instead of two. Also, it will work in all situations because the callback ref is bound to the lifecycle of the dom node, not of the component that mounts it. Further, it will not execute twice in strict mode (when running in the development environment), which seems to be important to many.&lt;/p&gt;

&lt;p&gt;And as shown in this &lt;a href="https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node"&gt;hidden gem in the (old) react docs&lt;/a&gt;, you can use it to run any sort of side effects, e.g. call &lt;em&gt;setState&lt;/em&gt; in it. I'll just leave the example here because it's actually pretty good:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MeasureExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;measuredRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;measuredRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, world&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;The above header is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;px tall&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So please, if you need to interact with DOM nodes directly after they rendered, try not to jump to &lt;em&gt;useRef&lt;/em&gt; + &lt;em&gt;useEffect&lt;/em&gt; directly, but consider using &lt;em&gt;callback refs&lt;/em&gt; instead.&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>React Query and Forms</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Mon, 27 Jun 2022 13:57:18 +0000</pubDate>
      <link>https://dev.to/tkdodo/react-query-and-forms-4odi</link>
      <guid>https://dev.to/tkdodo/react-query-and-forms-4odi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: Please note that I will be using &lt;a href="https://react-hook-form.com/"&gt;react-hook-form&lt;/a&gt; throughout this article, merely because I think it's a great library. That doesn't mean that the shown patterns will only work with react-hook-form - the concepts are applicable to any form library, and also if you are not using a form library at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Forms are an important part in many web applications as the primary means to update data. We are using React Query not only to fetch data (&lt;a href="https://tkdodo.eu/blog/react-query-as-a-state-manager"&gt;queries&lt;/a&gt;), but also to modify it (&lt;a href="https://tkdodo.eu/blog/mastering-mutations-in-react-query"&gt;mutations&lt;/a&gt;), so we need to somehow integrate our beloved async state manager with forms.&lt;/p&gt;

&lt;p&gt;The good news is that realistically, there isn't anything special about forms: It is still just a bunch of html elements that we render in order to display some data. However, as we'd also like to &lt;em&gt;change&lt;/em&gt; that data, the lines between what is Server State and what is Client State start to blur a bit, which is where the complexity might come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server State vs. Client State
&lt;/h2&gt;

&lt;p&gt;To recap, &lt;em&gt;Server State&lt;/em&gt; is state that we do not own, that is mostly async and where we only see a snapshot of how the data looked like the last time we fetched it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Client State&lt;/em&gt; is state that the frontend has full control over, is mostly synchronous and where we know the accurate value of it at all times.&lt;/p&gt;

&lt;p&gt;When we display a list of Persons, that is undoubtedly Server State. But what happens when we click on a Person to show their details in a Form with the intention of maybe updating some values? Does that Server State now become Client State? Is it a hybrid?&lt;/p&gt;

&lt;h2&gt;
  
  
  The simple approach
&lt;/h2&gt;

&lt;p&gt;I have gone on the record already about how I am not a fan of copying state from one state manager to another, be it &lt;a href="https://tkdodo.eu/blog/putting-props-to-use-state"&gt;putting props to state&lt;/a&gt; or copying state from &lt;a href="https://tkdodo.eu/blog/practical-react-query#keep-server-and-client-state-separate"&gt;React Query to local state&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I do think that forms can be an exception to this rule though, if you are doing it deliberately and know about the tradeoffs (everything is a tradeoff after all). When rendering our Person form, we very likely want to treat the Server State as &lt;em&gt;initial&lt;/em&gt; data only. We fetch the firstName and lastName, put it into the form state, and then let the user update it.&lt;/p&gt;

&lt;p&gt;Let's take a look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;PersonDetail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatePerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Last&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works incredibly well - so what are those tradeoffs?&lt;/p&gt;

&lt;h3&gt;
  
  
  Data might be undefined
&lt;/h3&gt;

&lt;p&gt;You might know that &lt;em&gt;useForm&lt;/em&gt; would also take defaultValues directly for the whole form, which would be pretty nice for larger forms. However, because we cannot call hooks conditionally, and because our &lt;em&gt;data&lt;/em&gt; is &lt;em&gt;undefined&lt;/em&gt; on the first render cycle (as we need to fetch it first), we cannot just do this in the same component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// 🚨 this will initialize our form with undefined&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;defaultValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'd have the same problem when copying into &lt;em&gt;useState&lt;/em&gt;, or when using uncontrolled forms (which react-hook-form does under the hood by the way). The best solution to this would be to split up the form into its own component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;PersonDetail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatePerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PersonForm&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;PersonForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;defaultValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Last&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not too bad, as it separates our data fetching from the presentation. I'm personally not a big fan of such a split, but it does get the job done here.&lt;/p&gt;

&lt;h3&gt;
  
  
  No background updates
&lt;/h3&gt;

&lt;p&gt;React Query is all about keeping your UI up-to-date with Server State. As soon as we copy that state somewhere else, React Query cannot do its job anymore. if a background refetch happens for whatever reason, and it yields new data, our form state will not update with it. This is likely not problematic if we are the only one working on that form state (like a form for our profile page). If that's the case, we should likely at least disable background updates by setting a higher &lt;em&gt;staleTime&lt;/em&gt; on our query. After all, why would we keep querying our server if the updates will not be reflected on the screen?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ opt out of background updates&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This approach can get problematic on bigger forms and in collaborative environments. The bigger the form, the longer it takes our users to fill it out. If multiple people work on the same form, but on different fields, whoever updates last might override the values that others have changed, because they still see a partially outdated version on their screen.&lt;/p&gt;

&lt;p&gt;Now react hook form allows you to detect which fields have been changed by the user and only send "dirty" fields to the server with some user land code (see &lt;a href="https://codesandbox.io/s/react-hook-form-submit-only-dirty-fields-ol5d2"&gt;the example here&lt;/a&gt;), which is pretty cool. However, this still doesn't show the latest values with updates made by other users to you. Maybe you would change your input had you known that a certain field was changed in the meantime by someone else.&lt;/p&gt;

&lt;p&gt;So what would we need to do to still reflect background updates while we are editing our form?&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping background updates on
&lt;/h2&gt;

&lt;p&gt;One approach is to rigorously separate the states. We'll keep the Server State in React Query, and only track the changes the user has made with our Client State. The source of truth that we display then to our users is &lt;em&gt;derived state&lt;/em&gt; from those two: If the user has changed a field, we show the Client State. If not, we fall back to the Server State:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;PersonDetail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatePerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Controller&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="c1"&gt;// ✅ derive state from field value (client state)&lt;/span&gt;
              &lt;span class="c1"&gt;// and data (server state)&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Last&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Controller&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that approach, we can keep background updates on, because it will still be relevant for untouched fields. We are no longer bound to the initialState that we had when we first rendered the form. As always, there are caveats here as well:&lt;/p&gt;

&lt;h3&gt;
  
  
  You need controlled fields
&lt;/h3&gt;

&lt;p&gt;As far as I'm aware, there is no good way to achieve this with uncontrolled fields, which is why I've resorted to using controlled fields in the above example. Please let me know if I'm missing something.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deriving state might be difficult
&lt;/h3&gt;

&lt;p&gt;This approach works best for shallow forms, where you can easily fall back to the Server State using nullish coalesce, but it could be more difficult to merge properly with nested objects. It might also sometimes be a questionable user experience to just change form values in the background. A better idea might be to just highlight values that are out of sync with the Server State and let the user decide what to do.&lt;/p&gt;




&lt;p&gt;Whichever way you choose, try to be aware of the advantages / disadvantages that each approach brings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips and Tricks
&lt;/h2&gt;

&lt;p&gt;Apart from those two principal ways of setting up your form, here are some smaller, but nonetheless important tricks to integrate React Query with forms:&lt;/p&gt;

&lt;h3&gt;
  
  
  Double submit prevention
&lt;/h3&gt;

&lt;p&gt;To prevent a form from being submitted twice, you can use the &lt;em&gt;isLoading&lt;/em&gt; prop returned from &lt;em&gt;useMutation&lt;/em&gt;, as it will be true for as long as our mutation is running. To disable the form itself, all you need to do is to disable the primary submit button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatePerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Invalidate and reset after mutation
&lt;/h3&gt;

&lt;p&gt;If you do not redirect to a different page right after the form submission, it might be a good idea to reset the form &lt;em&gt;after&lt;/em&gt; the invalidation has completed. As described in &lt;a href="https://tkdodo.eu/blog/mastering-mutations-in-react-query#some-callbacks-might-not-fire"&gt;Mastering Mutations&lt;/a&gt;, you'd likely want to do that in the &lt;em&gt;onSuccess&lt;/em&gt; callback of &lt;em&gt;mutate&lt;/em&gt;. This also works best if you keep state seperated, as you only need to reset to &lt;em&gt;undefined&lt;/em&gt; in order for the server state to be picked up again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;PersonDetail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQueryClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatePerson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ return Promise from invalidation&lt;/span&gt;
    &lt;span class="c1"&gt;// so that it will be awaited&lt;/span&gt;
    &lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidateQueries&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;
        &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="c1"&gt;// ✅ rest client state back to undefined&lt;/span&gt;
          &lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Controller&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Hooks, Dependencies and Stale Closures</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Mon, 25 Apr 2022 18:32:55 +0000</pubDate>
      <link>https://dev.to/tkdodo/hooks-dependencies-and-stale-closures-2lmc</link>
      <guid>https://dev.to/tkdodo/hooks-dependencies-and-stale-closures-2lmc</guid>
      <description>&lt;p&gt;Working with &lt;a href="https://en.wikipedia.org/wiki/Closure_(computer_programming)"&gt;closures&lt;/a&gt; is something that can become quite tricky, especially when dealing with hooks that have dependencies in React (think &lt;em&gt;useEffect&lt;/em&gt;, &lt;em&gt;useMemo&lt;/em&gt;, &lt;em&gt;useCallback&lt;/em&gt;). A lot of bugs and frustration are tied pretty closely to that concept - even though it is nothing that React itself introduced. It's rather a language concept that hooks rely upon.&lt;/p&gt;

&lt;p&gt;I love this question from Mark Erikson:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--iz1PmfdY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/842582724737163264/tFKLiJI5_normal.jpg" alt="Mark Erikson profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Mark Erikson
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @acemarke
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Question for the React community:&lt;br&gt;&lt;br&gt;Has the shift from "how does `this`/binding work?"-type questions to "why is my state stale due to closures?"-type questions made things better, worse, or just "same thing but different" ?&lt;br&gt;&lt;br&gt;(Inspired by the questions we see in &lt;a href="https://twitter.com/reactiflux"&gt;@reactiflux&lt;/a&gt; daily)
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      02:15 AM - 06 Aug 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1291196140965302272" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1291196140965302272" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1291196140965302272" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;To me, it has gotten subjectively better. Working with &lt;em&gt;this&lt;/em&gt; in class components was a pain, and errors did mostly show up at runtime. However, the behaviour you get due to stale closures are more subtle, and come up in more edge cases. The big advantage though is that they can be statically analyzed - and that's exactly what the &lt;a href="https://reactjs.org/docs/hooks-rules.html#eslint-plugin"&gt;react-hooks/exhaustive-deps&lt;/a&gt; eslint rule does.&lt;/p&gt;

&lt;p&gt;In this article, I'll try to break down what stale closures are, what they have to do with React and hooks, and why the lint rule is so important that I think you should set it to &lt;em&gt;error&lt;/em&gt;. To get there, we must first understand what (stale) closures are:&lt;/p&gt;

&lt;h2&gt;
  
  
  What are closures
&lt;/h2&gt;

&lt;p&gt;I find the concept of closures somewhat hard to explain. Let's take a look at the definition on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures"&gt;MDN&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I would best rephrase this as: JavaScript functions can "see", and interact with, things that were defined outside of them. You might not know it, but you are probably using this concept &lt;em&gt;very&lt;/em&gt; often, for example, when using props of your React component inside a callback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 💡 accessing count from the outer scope&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Show&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;logCount&lt;/em&gt; can access everything we define in the &lt;em&gt;Counter&lt;/em&gt; component, for example, the &lt;em&gt;count&lt;/em&gt; prop. You can easily check that you are relying on closures by moving the function to the outside of its parent. If it doesn't work anymore, it's because you don't have access to something you were "closing over" anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ 'count' is not defined. (no-undef)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Show&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nice part about closures in React is that it will "just work" if your component re-renders with a new prop. Have a look at this examples (note: examples are interactive on my blog: &lt;a href="https://tkdodo.eu/blog/hooks-dependencies-and-stale-closures"&gt;https://tkdodo.eu/blog/hooks-dependencies-and-stale-closures&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can click both buttons a bunch of times, and you should see that the log function, which closures over &lt;em&gt;count&lt;/em&gt;, will always have access to the "latest" count. Or so it seems.&lt;/p&gt;

&lt;p&gt;But why is that, and is that always true?&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking a picture
&lt;/h2&gt;

&lt;p&gt;The last sentence of the MDN definition is the most important one, so let's have another look (emphasis mine):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In JavaScript, closures are created every time a function is created, &lt;strong&gt;at function creation time.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me try to explain this with an analogy that has made closures "click" for me:&lt;/p&gt;

&lt;p&gt;Suppose every time you are creating a function, you are taking a picture of it. That picture contains everything from the moment when the picture was created. In the foreground, you have the most important things (what the function is doing, the code it is executing etc.). In the background of the picture, you have everything that lives outside your function, but that you are also using inside. It's as if the &lt;em&gt;count&lt;/em&gt; variable has photo-bombed our picture - it is also in it.&lt;/p&gt;

&lt;p&gt;The thing about the picture is - it &lt;em&gt;cannot&lt;/em&gt; change. Once we have taken it, its content is sealed (unless we use photoshop).&lt;/p&gt;

&lt;p&gt;Calling a function is just looking at the picture and doing what's on it. We will then see everything from the time when it was created.&lt;/p&gt;

&lt;p&gt;Every time the function is created, we throw away the old picture and take a new one. When React re-renders a component tree, it just re-runs everything top down. Here, this works to our advantage: Our &lt;em&gt;logCount&lt;/em&gt; function gets re-created because the &lt;em&gt;App&lt;/em&gt; component re-renders when the &lt;em&gt;count&lt;/em&gt; state is updated.&lt;/p&gt;

&lt;p&gt;Because of that, we take a new picture (= re-create the &lt;em&gt;logCount&lt;/em&gt; function), that contains the "latest" count variable. So when we click our button, we know the correct count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization
&lt;/h2&gt;

&lt;p&gt;For 98% of the code we write, this behaviour is great, and as I said, it just works. We don't even have to think about closures. That is, until we introduce memoization.&lt;/p&gt;

&lt;p&gt;The remainder of the time, re-creating a function every render just doesn't cut it. Maybe we need to pass it to a memoized child component that is expensive to re-render, so we have memoized it.&lt;/p&gt;

&lt;p&gt;For these cases, React offers ways to &lt;em&gt;not&lt;/em&gt; create functions (or values) every time, in the form of &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecallback"&gt;useCallback&lt;/a&gt; and &lt;a href="https://reactjs.org/docs/hooks-reference.html#usememo"&gt;useMemo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By allowing us to pass a dependency array to those hooks, we can let React know when it should re-create those things, and when it is safe to give us an old version of it.&lt;/p&gt;

&lt;p&gt;It comes with the aforementioned eslint rule that tries to point us in the right direction, and tells us which dependencies we should include. Because the rule is set to &lt;em&gt;warn&lt;/em&gt; per default, it seems like an innocent thing to ignore. But it is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignoring the linter
&lt;/h3&gt;

&lt;p&gt;Oftentimes, I see people ignore the rule with arguments like: "I only want to run this effect when the component mounts", or: "I only want to create the function once".&lt;/p&gt;

&lt;p&gt;Whenever you do that, no new picture is taken. React will just give you the old one to look at. And as we now know, that means we'll have the old photo-bombed variables at our disposal, as opposed to "the latest ones". And that is commonly referred to as a "stale closure". Because the things you are seeing are not up-to-date, but stale.&lt;/p&gt;

&lt;p&gt;We can see how ignoring the linter in our example will lead to non working code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 🚨 the linter says we should include count&lt;/span&gt;
  &lt;span class="c1"&gt;// as a dependency, but we don't&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We instruct React to only create our &lt;em&gt;logCount&lt;/em&gt; function once, "on mount". It doesn't have any dependencies (an empty dependency array), so it will always "see" the count from the first render cycle, which is 1. Every time we click the button, it will log 1. This is certainly not what we had in mind.&lt;/p&gt;




&lt;p&gt;Obviously, this was a very basic example. We can just include the count in the dependency Array, like the linter wants to, without problems. If count changes, we get a new picture. If our App re-renders for some other reason and count stays the same, we don't have to create a new function, and React can give us the old one. Nothing is stale here, because the only dependency we have is &lt;em&gt;count&lt;/em&gt;, and that hasn't changed. This is pretty sweet.&lt;/p&gt;

&lt;p&gt;But what about more complex dependencies? Like an object or a callback function that get provided via props that are &lt;em&gt;not&lt;/em&gt; referentially stable?&lt;/p&gt;

&lt;h2&gt;
  
  
  Another example
&lt;/h2&gt;

&lt;p&gt;Once upon a time, we had a component that wasn't fast. It looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;SlowComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RenderSomethingSlow&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our idea was to memoize it by wrapping it in &lt;a href="https://reactjs.org/docs/react-api.html#reactmemo"&gt;React.memo&lt;/a&gt; so that it doesn't get rendered too often. Because &lt;em&gt;onChange&lt;/em&gt; is a function that gets passed in by consumers, &lt;em&gt;they&lt;/em&gt; would need to memoize the function to not make the component slow again.&lt;/p&gt;

&lt;p&gt;We thought: "We actually only want to re-render our component when &lt;em&gt;value&lt;/em&gt; changes, so why don't we just omit the &lt;em&gt;onChange&lt;/em&gt; prop from the comparison function and side-step that problem?" 🤔&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FastComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;SlowComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the React docs suggest, we can "return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false".&lt;/p&gt;

&lt;p&gt;We only care about &lt;em&gt;value&lt;/em&gt; for our render result, so what's wrong with this approach?&lt;/p&gt;

&lt;p&gt;The answer lies again in &lt;em&gt;stale closures&lt;/em&gt;: If the caller component re-creates &lt;em&gt;onChange&lt;/em&gt; for some reason, but &lt;em&gt;value&lt;/em&gt; doesn't change, we are not taking a new picture of our SlowComponent, which means it still sees the old &lt;em&gt;onChange&lt;/em&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 🚨 name can become stale&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FastComponent&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;logUser&lt;/em&gt; function closures over &lt;em&gt;name&lt;/em&gt; and &lt;em&gt;count&lt;/em&gt;, but &lt;em&gt;FastComponent&lt;/em&gt; knows nothing of the &lt;em&gt;name&lt;/em&gt; prop. It will only be re-created when &lt;em&gt;value&lt;/em&gt; changes, so if &lt;em&gt;onChange&lt;/em&gt; is called, it sees the &lt;em&gt;name&lt;/em&gt; from the last time &lt;em&gt;count&lt;/em&gt; has changed - which might or might not be stale.&lt;/p&gt;

&lt;p&gt;This is a very tricky situation to be in, because your application can run perfectly fine for weeks or even months before you get a bug report that is likely very tricky to reproduce.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't lie
&lt;/h2&gt;

&lt;p&gt;The best thing you can do is: Don't get yourself in this situation by lying about the dependencies. Functions cannot be easily excluded from dependency arrays, so take the linter seriously, and make that rule an &lt;em&gt;error&lt;/em&gt; in your codebase!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler&lt;/strong&gt;: There &lt;em&gt;are&lt;/em&gt; ways to have your cake and eat it, too, but I will leave that for the next article. 😄&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below. ⬇️&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Offline React Query</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Mon, 14 Feb 2022 19:26:45 +0000</pubDate>
      <link>https://dev.to/tkdodo/offline-react-query-2kjc</link>
      <guid>https://dev.to/tkdodo/offline-react-query-2kjc</guid>
      <description>&lt;p&gt;I've said it time and time again - React Query is an &lt;a href="https://tkdodo.eu/blog/react-query-as-a-state-manager" rel="noopener noreferrer"&gt;async state manager&lt;/a&gt;. As long as you give it a Promise, resolved or rejected, the library is happy. Doesn't matter where that Promise comes from.&lt;/p&gt;

&lt;p&gt;There are many ways to produce promises, but by far the biggest use-case is data fetching. Very often, that requires an active network connection. But sometimes, especially on mobile devices where the network connection can be unreliable, you need your app to also work without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues in v3
&lt;/h2&gt;

&lt;p&gt;React Query is very well-equipped to handle offline scenarios. Because it provides a caching layer, as long as the cache is filled, you can keep working even if you don't have a network connection. Let's look at a couple of edge-case scenarios where v3 will not work as expected. I will use our basic post list / post detail &lt;a href="https://react-query.tanstack.com/examples/basic" rel="noopener noreferrer"&gt;example from the docs&lt;/a&gt; for illustration:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) no data in the cache
&lt;/h3&gt;

&lt;p&gt;As I said, in v3, things work well as long as the cache is filled. An edge case scenario where things get weird would be the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a good network connection and navigate to the list view&lt;/li&gt;
&lt;li&gt;You lose connection and click on a post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyjnwyz1knvyd11ofna8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyjnwyz1knvyd11ofna8.gif" alt="loading forever"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happens is that your query will stay in &lt;em&gt;loading&lt;/em&gt; state until you regain connection. Also, you can see a failed network request in the browser devtools. That is because React Query will always fire off the first request, and if that fails, it will pause retries if you have no network connection.&lt;/p&gt;

&lt;p&gt;Further, the React Query Devtools will show that your query is &lt;em&gt;fetching&lt;/em&gt;, which is not entirely true. The query is actually &lt;em&gt;paused&lt;/em&gt;, but we have no concept to represent that state - it's a hidden implementation detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) no retries
&lt;/h3&gt;

&lt;p&gt;Similarly, if you have turned off retries altogether in the above scenario, your query will go to error state immediately, with no way of stopping that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnfq4vz3lm7fz0pjii1h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnfq4vz3lm7fz0pjii1h.gif" alt="network error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why do I need &lt;em&gt;retries&lt;/em&gt; for my query to &lt;em&gt;pause&lt;/em&gt; if I have no network connection 🤷‍♂️?&lt;/p&gt;

&lt;h3&gt;
  
  
  3) queries that don't need the network
&lt;/h3&gt;

&lt;p&gt;Queries that don't need a network connection to work (e.g. because they do an expensive async processing in a web worker) will be paused until you regain network connection if they fail for some other reason. Also, those queries won't run on window focus because that feature is completely disabled if you have no network connection.&lt;/p&gt;




&lt;p&gt;In summary, there are two major issues: In some cases, React Query assumes that network connection is needed when that might not be true (case 3), and in other cases, React Query fires off a query even though it probably shouldn't (cases 1 and 2).&lt;/p&gt;

&lt;h2&gt;
  
  
  The new NetworkMode
&lt;/h2&gt;

&lt;p&gt;In v4, we've tried to tackle this problem holistically with a new &lt;em&gt;networkMode&lt;/em&gt; setting. With this, we can clearly distinguish between &lt;em&gt;online&lt;/em&gt; and &lt;em&gt;offline&lt;/em&gt; queries. It is an option for &lt;em&gt;useQuery&lt;/em&gt; as well as &lt;em&gt;useMutation&lt;/em&gt;, which means you can set it globally or on a per-query basis. After all, you might have some queries that need network connection, and some that don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  online
&lt;/h3&gt;

&lt;p&gt;This is the new default mode in v4, as we expect most users to use React Query in combination with data fetching. In short, with this setting, we assume that a query can only run if it has an active network connection.&lt;/p&gt;

&lt;p&gt;So what happens if you want to run a query that needs network connection when you don't have one? The query will go to a new &lt;em&gt;paused&lt;/em&gt; state. That &lt;em&gt;paused&lt;/em&gt; state is secondary to the main state that the query can be in: &lt;em&gt;idle&lt;/em&gt;, &lt;em&gt;loading&lt;/em&gt;, &lt;em&gt;success&lt;/em&gt; or &lt;em&gt;error&lt;/em&gt;, because you can lose your network connection at any time.&lt;/p&gt;

&lt;p&gt;This means you can be in &lt;em&gt;success&lt;/em&gt; state and &lt;em&gt;paused&lt;/em&gt;, for example, if you've fetched data successfully once but a background refetch got paused.&lt;/p&gt;

&lt;p&gt;Or, you can be in &lt;em&gt;loading&lt;/em&gt; state and &lt;em&gt;paused&lt;/em&gt; if a query mounts for the first time.&lt;/p&gt;

&lt;h4&gt;
  
  
  fetchStatus
&lt;/h4&gt;

&lt;p&gt;We've always had the &lt;em&gt;isFetching&lt;/em&gt; flag that indicated that a query was running. Similar to the new &lt;em&gt;paused&lt;/em&gt; state, a query could be &lt;em&gt;success&lt;/em&gt; and &lt;em&gt;fetching&lt;/em&gt;, or it could be &lt;em&gt;error&lt;/em&gt; and &lt;em&gt;fetching&lt;/em&gt;. Background refetches give you a &lt;em&gt;lot&lt;/em&gt; of possible states to be in (👋 state machines).&lt;/p&gt;

&lt;p&gt;As &lt;em&gt;fetching&lt;/em&gt; and &lt;em&gt;paused&lt;/em&gt; are mutually exclusive, we've combined them into the new &lt;em&gt;fetchStatus&lt;/em&gt; that now gets returned from &lt;em&gt;useQuery&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fetching&lt;/code&gt;: The query is really executing - a request is in-flight.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;paused&lt;/code&gt;: The query is not executing - it is paused until you have regained your connection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;idle&lt;/code&gt;: The query is currently not running.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a rule of thumb, the &lt;em&gt;status&lt;/em&gt; of the query will give you information about the &lt;em&gt;data&lt;/em&gt;: &lt;em&gt;success&lt;/em&gt; means you'll always have data, &lt;em&gt;loading&lt;/em&gt; means you don't have data yet. I thought about renaming the &lt;em&gt;loading&lt;/em&gt; state to &lt;em&gt;pending&lt;/em&gt;, but alas, this probably would have been "too breaking". 😅&lt;/p&gt;

&lt;p&gt;On the other hand, the &lt;em&gt;fetchStatus&lt;/em&gt; gives you information about the &lt;em&gt;queryFn&lt;/em&gt;: is it running or not? The &lt;code&gt;isFetching&lt;/code&gt; and &lt;code&gt;isPaused&lt;/code&gt; flags are derived from that status.&lt;/p&gt;




&lt;p&gt;Let's take a look at how case 1 from above can look like in v4. Please notice the new network mode toggle button in the RQ devtools. It's pretty cool because it doesn't actually turn off your network - it just makes React Query &lt;em&gt;believe&lt;/em&gt; that there is no network for testing purposes. Yes, I am quite proud of it. 😊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9nod4qqvifuz8awwtom.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9nod4qqvifuz8awwtom.gif" alt="paused"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can clearly see the state the query is in (&lt;em&gt;paused&lt;/em&gt;) due to the new purple status badge. Also, the first network request is made once we turn the network back on.&lt;/p&gt;

&lt;h3&gt;
  
  
  always
&lt;/h3&gt;

&lt;p&gt;In this mode, React Query does not care about your network connection at all. Queries will always fire, and they will never be paused. This is most useful if you use React Query for something &lt;em&gt;other than&lt;/em&gt; data fetching.&lt;/p&gt;

&lt;h3&gt;
  
  
  offlineFirst
&lt;/h3&gt;

&lt;p&gt;This mode is very similar to how React Query worked in v3. The first request will &lt;em&gt;always&lt;/em&gt; be made, and if that fails, retries will be paused. This mode is useful if you're using an additional caching layer like the browser cache on top of React Query.&lt;/p&gt;

&lt;p&gt;Let's take the GitHub repo API as an example. It sends the following response headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cache-control: public, max-age=60, s-maxage=60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which means that for the next 60 seconds, if you request that resource again, the response will come from the browser cache. The neat thing about this is that it works while you're offline, too! Service workers, e.g. for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers" rel="noopener noreferrer"&gt;offline first PWAs&lt;/a&gt;, work in a similar way by intercepting the network request and delivering cached responses if they are available.&lt;/p&gt;

&lt;p&gt;Now those things wouldn't work if React Query would decide to &lt;em&gt;not&lt;/em&gt; fire the request because you have no network connection, like the default &lt;em&gt;online&lt;/em&gt; mode does. To intercept a fetch request, it must happen :) So if you have this additional cache layer, make sure to use the &lt;em&gt;offlineFirst&lt;/em&gt; &lt;em&gt;networkMode&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If the first request goes out, and you hit the cache - great, your query will go to &lt;em&gt;success&lt;/em&gt; state, and you'll get that data. And if you have a cache miss, you'll likely get a network error, after which React Query will pause the retries, which will put your query into the &lt;em&gt;paused&lt;/em&gt; state. It's the best of both worlds. 🙌&lt;/p&gt;

&lt;h2&gt;
  
  
  What does all of this mean for me, exactly?
&lt;/h2&gt;

&lt;p&gt;Nothing, unless you want to. You can still decide to ignore that new &lt;em&gt;fetchStatus&lt;/em&gt; and only check for &lt;em&gt;isLoading&lt;/em&gt; - React Query will behave just like before (well - case 2 from above will even work better because you won't see the network error).&lt;/p&gt;

&lt;p&gt;However, if making your app robust for situations where you have no network connection is a priority for you, you now have the option to react to the exposed &lt;em&gt;fetchStatus&lt;/em&gt; and act accordingly.&lt;/p&gt;

&lt;p&gt;What you do with that new status is up to you. I'm excited to see which ux people will build on top of this. 🚀&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below ⬇️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Always provide customer value</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Sat, 29 Jan 2022 14:26:27 +0000</pubDate>
      <link>https://dev.to/tkdodo/always-provide-customer-value-4g2f</link>
      <guid>https://dev.to/tkdodo/always-provide-customer-value-4g2f</guid>
      <description>&lt;p&gt;Last time, I told you when &lt;em&gt;not&lt;/em&gt; to start a refactoring and kind of left you hanging when it comes to the question: When is the right time? Let's try to answer that now!&lt;/p&gt;

&lt;p&gt;To do that, we must first divide our potential refactorings into groups:&lt;/p&gt;

&lt;h2&gt;
  
  
  The small ones
&lt;/h2&gt;

&lt;p&gt;A small refactoring is one that you are comfortable doing at all times. It's those little things that get suggested in a code review right before you actually wanted to ship it, and oftentimes, it's something that can even be automatically done by your IDE.&lt;/p&gt;

&lt;p&gt;Renaming a variable. Extracting a function. Inlining an abstraction.&lt;/p&gt;

&lt;p&gt;As engineers, it is a) our job and b) in our own best interest to produce great quality code. Whenever the circumstances allow it (see also &lt;a href="https://tkdodo.eu/blog/road-to-refactoring"&gt;#1: Don't mix refactorings with hotfixes&lt;/a&gt;), we should take the liberty to improve maintainability without asking for permission - no matter if we are fixing a bug or adding a feature.&lt;/p&gt;

&lt;p&gt;It's like writing tests. Or making sure that our app is accessible.&lt;/p&gt;

&lt;p&gt;It is something that I would expect anyone on my team to be passionate about. We care about our codebase, and we want to make it better with everything that we are doing.&lt;/p&gt;

&lt;p&gt;Incrementally. One tiny refactoring at a time.&lt;/p&gt;

&lt;p&gt;Of course, you'll have more confidence if the part you are touching is sufficiently covered with types and tests. If it is not, I would suggest that's where you start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add types.&lt;/li&gt;
&lt;li&gt;Add tests.&lt;/li&gt;
&lt;li&gt;Then refactor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that order. If you only make it to one or to two, that's alright. There is always a next time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger ones
&lt;/h2&gt;

&lt;p&gt;Yes, not all refactorings are that small. Sometimes, you stumble upon an architecture that is flawed and needs to be changed. Or you see an outdated pattern that you have left behind long ago (or so you thought), and you really don't want to add more code to the mess before cleaning it up.&lt;/p&gt;

&lt;p&gt;How far you go with ad-hoc refactorings is up to you and your team, and needs a bit of experience and "feeling" for the codebase. I have started refactorings that I thought were small, only to go from one rabbit hole to the next to reverting everything after two days. It sucks, but you learn from it 😄.&lt;/p&gt;

&lt;p&gt;Once you decide that a refactoring is larger than something that you can just do on the fly, you have to somehow plan it into your sprint (or whatever way of working your team has adopted). My advice for these situations would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always provide customer value&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pure refactoring issues, apart from the small ones, are rarely a good idea. It just doesn't sell very well:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm gonna work on this refactoring, it's about 20 story points, and it's gonna take a good amount of time. In the best case scenario, everything will still work exactly the same as before, while in the worst case, I'll introduce a bunch of regressions with it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— A dev selling a refactoring&lt;/p&gt;

&lt;p&gt;That doesn't sound too good for a product manager. Why would this be more important than the new feature the customer really wants?&lt;/p&gt;

&lt;p&gt;Yes, it's an investment into the future of the product, it makes it more maintainable, and you'll likely have higher velocity later on while also producing fewer bugs. But "bugs we would have in production without this refactoring" is a very hard metric to measure. So likely, if you come up with a proposal like that, it will be squashed for not providing enough &lt;em&gt;direct value&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The right package
&lt;/h3&gt;

&lt;p&gt;For larger refactorings, it is important to wrap them in the right package:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, we can add this new feature the customer wants, but it's a technical requirement that we also re-architect this page because it will be too hard otherwise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— selling a "refactoring feature"&lt;/p&gt;

&lt;p&gt;That is something most people can get behind. It might take a bit longer to ship the actual feature, but it's a good compromise where both "sides" get their win.&lt;/p&gt;

&lt;p&gt;As an example, we had a quite complex filter component that we used in some parts of the application. When a new feature for this component was due, we decided to port it to react-query while doing so. This delivered the needed &lt;em&gt;direct value&lt;/em&gt; (the feature for the customer), while also providing &lt;em&gt;implied value&lt;/em&gt; (less code, better maintainability).&lt;/p&gt;

&lt;h2&gt;
  
  
  The huge ones
&lt;/h2&gt;

&lt;p&gt;These don't come up that often, and are likely rewrites of a big part of the application. Maybe you want to replace redux-saga with react-query? Maybe it's time to move to &lt;a href="https://remix.run/"&gt;remix&lt;/a&gt;? Our migration from &lt;a href="https://tkdodo.eu/blog/flow-to-type-script-migration-journey"&gt;flow to typescript&lt;/a&gt; some time ago would also qualify.&lt;/p&gt;

&lt;p&gt;How on earth can you get everyone on board for such an endeavor? This will be the topic of part 3 - so stay tuned 📻&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below ⬇️&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>principles</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Road to Refactoring</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Sat, 29 Jan 2022 14:24:02 +0000</pubDate>
      <link>https://dev.to/tkdodo/road-to-refactoring-4ep7</link>
      <guid>https://dev.to/tkdodo/road-to-refactoring-4ep7</guid>
      <description>&lt;p&gt;Over the years, I've come to work on many medium to large scale code bases. Most of these have organically grown over time, some of them being full of &lt;a href="https://mikehadlow.blogspot.com/2014/12/the-lava-layer-anti-pattern.html"&gt;Lava Layers&lt;/a&gt;. Doing a &lt;a href="https://en.wikipedia.org/wiki/Code_refactoring"&gt;refactoring&lt;/a&gt; in those code bases is often not trivial. Incidental complexity is high, test coverage is low. There are more features than you can count.&lt;/p&gt;

&lt;p&gt;Also, where do you start? There are so many things you'd like to tackle and do differently, but everything you touch has the potential to introduce regressions.&lt;/p&gt;

&lt;p&gt;In this series, I'm trying to list some of the things that I've done to make refactorings a success rather than a disaster. This is by no means an exhaustive lists, and is heavily biased by my personal experience. Further, it likely doesn't apply to your side-project or early start-up, so as usual, your mileage may vary. That being said, here we go with the first tip 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't mix refactorings with hotfixes
&lt;/h2&gt;

&lt;p&gt;You get a bug report, highest prio, customer is escalating, account management is permanently asking: "what is the ETA on this, what can I tell the customer?"&lt;/p&gt;

&lt;p&gt;You look at the code and analyze the issue. Maybe it's in an area of the code base that hasn't been touched for a while, or maybe you've not looked at it in a longer time.&lt;/p&gt;

&lt;p&gt;Likely, you won't like what you see. Software patterns, especially in the frontend world, can evolve rapidly. Even if you start with something new, chances are you would do it differently in a couple of months.&lt;/p&gt;

&lt;p&gt;Maybe you see a React Class Component that fetches in &lt;em&gt;componentDidMount&lt;/em&gt;. Wtf, we've moved to &lt;a href="https://react-query.tanstack.com/"&gt;react-query&lt;/a&gt; half a year ago, what is this? Or maybe there are some global styles or deprecated components being used. Oh, and this dependency could &lt;em&gt;really&lt;/em&gt; need an update...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.oreilly.com/library/view/97-things-every/9780596809515/ch08.html"&gt;Scout's principle&lt;/a&gt; - time to clean up this mess...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't. Just don't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's a time and a place for everything, but this is not the time for a refactoring. You don't want to prolong the actual fix. As an engineer, you are a problem solver, and your only goal here should be to fix the actual problem. Also, you might introduce another regression, and code reviews will take longer if you add unrelated changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality
&lt;/h3&gt;

&lt;p&gt;That doesn't mean we should compromise on quality. Even in those situations, we still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a branch (no direct merging to &lt;em&gt;main&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Write proper &lt;a href="https://tkdodo.eu/blog/avoiding-legacy-systems#commit-messages"&gt;commit messages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Get the required amount of reviews&lt;/li&gt;
&lt;li&gt;Run the CI pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And make sure that all other quality gates that we have set up still pass. We surely want a fix as fast as possible, but not at all costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  A failing test case
&lt;/h3&gt;

&lt;p&gt;This is the flow I usually take when getting a bug report:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ao3Ye5Sn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1428810489157595139/lBT2YI9D_normal.jpg" alt="Dominik profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Dominik
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tkdodo"&gt;@tkdodo&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      This is the best flow:&lt;br&gt;🐞 find a bug &lt;br&gt;🕵️‍♂️ investigate it&lt;br&gt;⇆ reproduce it&lt;br&gt;🧪 write a failing test for it&lt;br&gt;💻 fix it&lt;br&gt;🟢 see the green test&lt;br&gt;🚀 ship it
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      16:32 PM - 22 Nov 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1462821229841338381" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1462821229841338381" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1462821229841338381" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Writing a failing test case &lt;em&gt;before&lt;/em&gt; you start fixing the issue is something I can really recommend, as it will ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the bug is consistently reproducible.&lt;/li&gt;
&lt;li&gt;the issue stays fixed in the future, for example, when you actually refactor that code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This presumes that you have a somewhat easy way to add a test case for the bug. If you're in the unfortunate situation that you'd have to introduce a testing framework first to actually write a test - go back to the beginning of this article 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  The right time
&lt;/h2&gt;

&lt;p&gt;So when is the right time to refactor the horrible thing we've found? I'll try to answer this in &lt;a href="https://tkdodo.eu/blog/always-provide-customer-value"&gt;part 2&lt;/a&gt; - so stay tuned 📻&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below ⬇️&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>principles</category>
      <category>javascript</category>
    </item>
    <item>
      <title>2021 in Review</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Thu, 30 Dec 2021 17:46:09 +0000</pubDate>
      <link>https://dev.to/tkdodo/2021-in-review-435e</link>
      <guid>https://dev.to/tkdodo/2021-in-review-435e</guid>
      <description>&lt;p&gt;Since I'm currently sitting at home on my couch, resting after my 3rd Covid-19 vaccine shot with not a lot else to do, I thought I'd reflect a bit on the year I've had and give a bit of an outlook of what's ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogging
&lt;/h2&gt;

&lt;p&gt;Not a lot has happened in the first five months of the year. I was getting more and more involved in open source, and I tried to blog regularly (about once every two or three weeks).&lt;/p&gt;

&lt;p&gt;There were two reasons why I started my blog last year: Because I thought it would be fun to set up (narrator: it was not), and because I wanted to have a permanent resource I could link people to. I've also made it a rule that if I see a concept / question / (anti-)pattern at least 3 times, I would blog about it.&lt;/p&gt;

&lt;p&gt;That was also the reason why I started my &lt;a href="https://tkdodo.eu/blog/practical-react-query" rel="noopener noreferrer"&gt;React Query related series of blog posts&lt;/a&gt;, which currently spans over 13 articles, as I have gotten a lot of questions around React Query.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Open Source
&lt;/h2&gt;

&lt;p&gt;2021 was definitely the year when I started to take open source seriously. I have contributed a little to open-source before, but the turning point came at around Mai 2021, when Tanner made me an official &lt;a href="https://react-query.tanstack.com/" rel="noopener noreferrer"&gt;React Query&lt;/a&gt; maintainer. Around the same time, I also became a maintainer for &lt;a href="https://remedajs.com/docs" rel="noopener noreferrer"&gt;remeda&lt;/a&gt;, my favourite TypeScript util library.&lt;/p&gt;

&lt;p&gt;With those new responsibilities, it became clear that I couldn't just continue like before. I was already overworked, and to be honest, open-source was a lot more fun than work at that time. I had cancelled almost all of my vacations due to Covid-19 and didn't feel fully happy.&lt;/p&gt;

&lt;p&gt;Being self-employed and catering to three different clients as a contractor, I made the decision to cancel one of my clients where I didn't feel my contributions were making much of a difference anymore, and introduced open-source-friday:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1414569849448194049-569" src="https://platform.twitter.com/embed/Tweet.html?id=1414569849448194049"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1414569849448194049-569');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1414569849448194049&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;It might sound crazy to cancel a paid engagement to work for free on open-source instead, but it was definitely the right move for me. It gave me a bit of freedom to work on what I believe in, which can be much more fulfilling than a pay-check.&lt;/p&gt;

&lt;p&gt;Tanner also convinced me to set up &lt;a href="https://github.com/sponsors/tkdodo" rel="noopener noreferrer"&gt;GitHub sponsors&lt;/a&gt;, where currently 18 amazing people are sponsoring my open source work 💖.&lt;/p&gt;

&lt;p&gt;Oddly enough, being a React Query maintainer led to some amazing new consulting opportunities for me as well. I ❤️ React Query and React + TypeScript in general, and I also enjoy teaching, so I definitely feel very privileged that I got the opportunity to combine these aspects.&lt;/p&gt;

&lt;p&gt;Later that summer, my blog even became a part of the official React Query docs. I'm very happy that people believe my content is good enough to be "official-docs" material, and it has kept me motivated to write more articles:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1432083106593480714-539" src="https://platform.twitter.com/embed/Tweet.html?id=1432083106593480714"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1432083106593480714-539');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1432083106593480714&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  React 18
&lt;/h2&gt;

&lt;p&gt;For the second half of the year, I kept an eye on React 18, the Working group, and how some changes would affect me as a user of React as well as a library maintainer. My probably biggest "contribution" in terms of impact in 2021 happened when I asked an innocent looking question to &lt;a href="https://twitter.com/dai_shi" rel="noopener noreferrer"&gt;Dasishi Kato&lt;/a&gt;, author of the state manager &lt;a href="https://zustand.surge.sh/" rel="noopener noreferrer"&gt;zustand&lt;/a&gt;, on Twitter:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1427922647401312257-62" src="https://platform.twitter.com/embed/Tweet.html?id=1427922647401312257"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1427922647401312257-62');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1427922647401312257&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h3&gt;
  
  
  useMutableSource -&amp;gt; useSyncExternalStore
&lt;/h3&gt;

&lt;p&gt;React 18 was about to ship a hook called &lt;em&gt;useMutableSource&lt;/em&gt;, and it required input selectors to be referentially stable. I stumbled upon this when I reviewed a PR at work, where a co-worker of mine memoized all selectors to a zustand store with &lt;em&gt;useCallback&lt;/em&gt;, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zustand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bears&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;increasePopulation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bears&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bears&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;

&lt;span class="c1"&gt;// usage:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bears&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bears&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]))&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increasePopulation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increasePopulation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Naturally, that got me thinking. Why would you memoize a selector that just returns a value from the state? That's not an expensive calculation, and &lt;em&gt;useCallback&lt;/em&gt; is just a performance optimization 🤔.&lt;/p&gt;

&lt;p&gt;The answer I got was surprising, as my co-worker said: The zustand docs recommend that!&lt;/p&gt;

&lt;p&gt;I looked it up, and yes, &lt;a href="https://github.com/pmndrs/zustand/blob/1242610103370a2a2729c1f5ab9b6720d24efb8e/readme.md#memoizing-selectors" rel="noopener noreferrer"&gt;it was really there&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is generally recommended to memoize selectors with useCallback. This will prevent unnecessary computations each render. It also allows React to optimize performance in concurrent mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;DaiShi's answer to my question why this was suggested was: Because it will be &lt;em&gt;required&lt;/em&gt; in React 18 to avoid infinite loops in concurrent mode.&lt;/p&gt;

&lt;p&gt;🤯&lt;/p&gt;

&lt;p&gt;After that, the discussion escalated a bit, as the redux team around &lt;a href="https://twitter.com/acemarke" rel="noopener noreferrer"&gt;Mark Erkison&lt;/a&gt; as well as react maintainers like &lt;a href="https://twitter.com/brian_d_vaughn" rel="noopener noreferrer"&gt;Brian Vaughn&lt;/a&gt; got pulled in as well. Eventually, the discussion moved towards the &lt;a href="https://github.com/reactwg/react-18/discussions/84" rel="noopener noreferrer"&gt;React 18 Working Group&lt;/a&gt;, which I was later also invited to, where the hook was renamed to &lt;em&gt;useSyncExternalStore&lt;/em&gt;, and the api was adjusted so that selector stability was no longer required.&lt;/p&gt;

&lt;p&gt;I'm glad my little tweet kicked off the discussion that led to this decision, which probably avoided massive breaking changes for many consumers. Just imagine having to memoize every inline selector in redux 😮. I do however regret the tone in which I voiced my concerns - I'm really sorry for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Query and React 18
&lt;/h3&gt;

&lt;p&gt;When react-redux released &lt;a href="https://github.com/reduxjs/react-redux/releases/tag/v8.0.0-alpha.0" rel="noopener noreferrer"&gt;v8.0.0-alpha.0&lt;/a&gt; in early October, I decided it's time to take a stab at making React Query ready for concurrent features, which will be shipped in React 18. Similar to redux, React Query has an external store that manages the cache, which components need to subscribe to. If we keep doing that with our current approach (basically, with &lt;em&gt;useEffect&lt;/em&gt; and &lt;em&gt;useState&lt;/em&gt;), applications might suffer from an issue called &lt;em&gt;tearing&lt;/em&gt;, where parts of the ui might display outdated values.&lt;/p&gt;

&lt;p&gt;If that concept is unfamiliar to you, there is a great talk from Dasishi Kato at React Conf 2021: &lt;a href="https://www.youtube.com/watch?v=oPfSC5bQPR8&amp;amp;list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&amp;amp;t=3s" rel="noopener noreferrer"&gt;React 18 for External Store Libraries&lt;br&gt;
&lt;/a&gt; about this topic.&lt;/p&gt;

&lt;p&gt;To solve this issue, React 18 will ship with a new hook called &lt;a href="https://github.com/reactwg/react-18/discussions/86" rel="noopener noreferrer"&gt;useSyncExternalStore&lt;/a&gt; (yes, the one I mentioned above 😅), which libraries like React Query or redux need to adopt.&lt;/p&gt;

&lt;p&gt;Right now, we have a &lt;a href="https://github.com/tannerlinsley/react-query/pull/3064" rel="noopener noreferrer"&gt;draft PR&lt;/a&gt; that passes all tests against React 17 &lt;em&gt;and&lt;/em&gt; React 18. Depending on when React 18 will become stable, we might include this PR in our next major release.&lt;/p&gt;
&lt;h2&gt;
  
  
  React Query v4
&lt;/h2&gt;

&lt;p&gt;Speaking of React Query: at the end of October, we decided to work towards a new major version of the library, as some inconsistencies have piled up, and some issues couldn't be fixed unless we tackled them holistically with a new approach. We put our minds together and came up with a great new "Network Mode" feature to iron out these inconsistencies and to make React Query even better 🚀.&lt;/p&gt;

&lt;p&gt;Version 4 is now in &lt;a href="https://github.com/tannerlinsley/react-query/releases/tag/v4.0.0-alpha.1" rel="noopener noreferrer"&gt;alpha&lt;/a&gt;, and we are looking forward to making a stable release sometime early next year. I will also very likely write a dedicated blog post about v4 in the near future.&lt;/p&gt;
&lt;h2&gt;
  
  
  Public Speaking
&lt;/h2&gt;

&lt;p&gt;At the end of the year, I got my first invitations to represent React Query at online Panel Discussions. As I've never done anything like that before, I was really, really nervous. Some people say this will get better over time, some say it doesn't 🤷‍♂️. Anyways, I don't like watching myself on those 🙈, but here are the links in case you missed it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=lg7X9wUBwWk" rel="noopener noreferrer"&gt;GraphQL Client-Side Libraries Panel Discussion - GraphQL Galaxy 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=7LMsR30p1xM" rel="noopener noreferrer"&gt;State of React | December 2021&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2021 in numbers
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The blog
&lt;/h3&gt;

&lt;p&gt;For my blog, I only have comparable metrics for the last 3 months, because I switched hosting provider and later analytics provider during the year. I am now with &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;netlify&lt;/a&gt; and I'm using &lt;a href="https://plausible.io/" rel="noopener noreferrer"&gt;plausible.io&lt;/a&gt; for analytics, and I'm supper happy with both.&lt;/p&gt;

&lt;p&gt;For that time period, I can see a steady stream of about &lt;strong&gt;20k&lt;/strong&gt; visitors and &lt;strong&gt;35k&lt;/strong&gt; page views per month, which is huge for my perspective, and definitely more than I would've ever thought would happen to my little blog.&lt;/p&gt;

&lt;p&gt;From what I can tell, most people come to my blog from Google (about 50% traffic!) and from the React Query docs (another 20%). The top 6 articles in terms of page views are also all from the React Query series:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15rwgzbsmqlywldthi9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15rwgzbsmqlywldthi9i.png" alt="metrics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also tried to blog regularly - about once every two to three weeks. I've written a total of 21 articles, and November was the only month without a blog post (mainly because I was working on React Query v4 instead).&lt;/p&gt;
&lt;h3&gt;
  
  
  Twitter
&lt;/h3&gt;

&lt;p&gt;This year, I've grown my twitter friends by about &lt;strong&gt;3500%&lt;/strong&gt; 😮. Of course, that number becomes less impressive if you consider that I started the year with under 100 followers, as percentages are high when the bar is low. I'm still pretty proud of it though, as I seek to provide valuable content for the community. I try not to give random TypeScript tips that you can easily find by going to google, or explain how &lt;em&gt;Array.map&lt;/em&gt; works in nice pictures. I think there are enough people on Twitter doing that already. Also, I'm &lt;em&gt;really&lt;/em&gt; not in it for the followers. I think there is a sweet spot for Twitter that is right between where you feel like you're shouting into the void (&amp;lt; 1k) vs. where your notifications are becoming unbearable (apparently &amp;gt; 10k, but I can't tell yet). I'm right in there, and it feels perfect at the moment 😊.&lt;/p&gt;

&lt;p&gt;The tweet that got the most impressions this year (&lt;strong&gt;74k&lt;/strong&gt;) was one I've quickly written on my phone after answering a certain question for the Nth time - which also lead to me writing &lt;a href="https://tkdodo.eu/blog/react-query-as-a-state-manager" rel="noopener noreferrer"&gt;React Query as a State Manager&lt;/a&gt; - arguably one of my best received articles:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1426902315429212162-109" src="https://platform.twitter.com/embed/Tweet.html?id=1426902315429212162"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1426902315429212162-109');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1426902315429212162&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  2022 and beyond
&lt;/h2&gt;

&lt;p&gt;I'm quite excited for what lies ahead. With React 18 and React Query v4 around the corner, the ecosystem just keeps getting better and better, which is to everyone's advantage.&lt;/p&gt;

&lt;p&gt;For 2022, I &lt;em&gt;really&lt;/em&gt; want to rewrite my blog, and go away from &lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;gatsby&lt;/a&gt; towards either &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;next.js&lt;/a&gt; or &lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;remix.run&lt;/a&gt; - or whichever framework will be all the rage next year. I don't want to do this because I'm unsatisfied with gatsby (I'm not), but more so for the technical challenge and to keep up-to-date with the latest developments on how to build stuff.&lt;/p&gt;

&lt;p&gt;So let me know in the comments below ⬇️ (or reach out to me on &lt;a href="https://twitter.com/tkdodo" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;) what you think I should be choosing and why. I really hope I find the time to get around to it 😀.&lt;/p&gt;

&lt;p&gt;With that, all that is left for me to say is merry Christmas 🎄 (if you are celebrating it), a happy new year 🎊, and I hope you say safe and healthy ⛑. I will be taking about two weeks time off to hopefully come back refreshed next year.&lt;/p&gt;

</description>
      <category>react</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Beware the leaking any</title>
      <dc:creator>Dominik D</dc:creator>
      <pubDate>Sun, 05 Dec 2021 14:16:21 +0000</pubDate>
      <link>https://dev.to/tkdodo/beware-the-leaking-any-5d2f</link>
      <guid>https://dev.to/tkdodo/beware-the-leaking-any-5d2f</guid>
      <description>&lt;p&gt;&lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any"&gt;Any&lt;/a&gt; is not among my favourite TypeScript types, but it is the one you will inevitably encounter, if you like it or not. This might not be a problem in some situations, but can be devastating in others. Let's dive into it:&lt;/p&gt;

&lt;h2&gt;
  
  
  A short introduction to the type system
&lt;/h2&gt;

&lt;p&gt;Any is the &lt;a href="https://en.wikipedia.org/wiki/Top_type"&gt;top type&lt;/a&gt; in TypeScript's type system (while &lt;a href="https://www.typescriptlang.org/docs/handbook/2/functions.html#never"&gt;never&lt;/a&gt; would be the bottom type). Think about the types as a big tree, where each child type "extends" its parent, but not the other way around. This is very convenient when you have an object hierarchy, like &lt;code&gt;Vehicle -&amp;gt; Car&lt;/code&gt;, because every Car is a Vehicle, but not every Vehicle is a Car.&lt;/p&gt;

&lt;p&gt;It does however also work on a much simpler level, for example with the string type and a string literal type. Every string literal is a sub-type of the type string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;em&gt;child&lt;/em&gt; would also "extend" &lt;em&gt;parent&lt;/em&gt;, even though we don't really have a typical inheritance. That's why it's often easier to replace "extends" with "is assignable to" when thinking about types.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;child is assignable to parent, but parent is not assignable to child.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parent is not assignable to child because it's type is wider. This can be proven by trying to actually assign the variables to each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ ok, as parent is the "wider" type&lt;/span&gt;
&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;
&lt;span class="c1"&gt;// 🚨 Type 'string' is not assignable to type '"hello"'.(2322)&lt;/span&gt;
&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can assign child to parent, because child is assignable to parent, but it doesn't work the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what about any?
&lt;/h2&gt;

&lt;p&gt;In any case (pun intended), &lt;em&gt;any&lt;/em&gt; would sit at the top of the tree. Everything is assignable to &lt;em&gt;any&lt;/em&gt;. If we add &lt;em&gt;any&lt;/em&gt; to the above example, our tree would be &lt;code&gt;any -&amp;gt; string -&amp;gt; 'hello'&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ ok, as parent is the "wider" type&lt;/span&gt;
&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;
&lt;span class="c1"&gt;// ✅ also fine&lt;/span&gt;
&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far so good, and if &lt;em&gt;any&lt;/em&gt; sits at the top, it must mean that you cannot assign it to a more narrow type, right? This is where things get weird with &lt;em&gt;any&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// 🚨 Type 'string' is not assignable to type '"hello"'.(2322)&lt;/span&gt;
&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;
&lt;span class="c1"&gt;// 🤯 no type error here&lt;/span&gt;
&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Any&lt;/em&gt; is an exception to this rule, because assignments work both ways, which make &lt;em&gt;any&lt;/em&gt; an escape hatch for the compiler. You can literally do &lt;em&gt;anything&lt;/em&gt; with it, even things that clearly won't work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unknown to the rescue
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type"&gt;TypeScript 3.0&lt;/a&gt;, the unknown top type was introduced to fix this. It is like the type-safe big brother to &lt;em&gt;any&lt;/em&gt;. If we replace &lt;em&gt;any&lt;/em&gt; with &lt;em&gt;unknown&lt;/em&gt;, we get the exact behavior we thought &lt;em&gt;any&lt;/em&gt; would give us.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Anything is assignable to unknown, but unknown isn’t assignable to anything but itself and any&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ ok, as parent is the "wider" type&lt;/span&gt;
&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;
&lt;span class="c1"&gt;// ✅ also fine&lt;/span&gt;
&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;
&lt;span class="c1"&gt;// 🚨 Type 'string' is not assignable to type '"hello"'.(2322)&lt;/span&gt;
&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;
&lt;span class="c1"&gt;// 🚨 Type 'unknown' is not assignable to type 'string'.(2322)&lt;/span&gt;
&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great, because now we have our real tree structure back with &lt;em&gt;unknown&lt;/em&gt; sitting at the top, but it also means it's virtually impossible to do anything meaningful with &lt;em&gt;unknown&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But that's okay.&lt;/p&gt;

&lt;p&gt;Because we don't know what it is, we have to find that out at runtime first. TypeScript will narrow the type if we perform a type narrowing check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ✅ top is of type string now, so it's assignable to parent&lt;/span&gt;
  &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many ways to &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html"&gt;narrow types&lt;/a&gt; in Typescript, like using typeof, instanceof, the in operator, checks like Array.isArray or even user defined type guards. Working this way is a much safer approach because it tries to leverage the compiler, not bypass it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When any is leaking
&lt;/h2&gt;

&lt;p&gt;Okay, we've probably all used &lt;em&gt;any&lt;/em&gt; from time to time to shut up the compiler, and that's not a problem. There are definitely diminishing returns when trying to go towards 100% type safety, and sometimes, it's just easier for everyone's sanity to disable the compiler via &lt;em&gt;any&lt;/em&gt; and write a bunch of unit tests to make sure you don't screw up along the line.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Any&lt;/em&gt; becomes problematic when the scope is large, because it will disable the compiler in places you didn't think about. Let's have another look at what the TypeScript docs have to say about &lt;em&gt;any&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a value is of type any, you can access any properties of it (which will in turn be of type any), call it like a function, assign it to (or from) a value of any type, or pretty much anything else that’s syntactically legal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any"&gt;The TypeScript docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This basically means if you have an &lt;em&gt;any&lt;/em&gt;, and you call a function on it, the result will also be &lt;em&gt;any&lt;/em&gt;. Every property will be &lt;em&gt;any&lt;/em&gt;. Every function you return it from will then return &lt;em&gt;any&lt;/em&gt;. If you use the return value of this function in a computation, the result will also be &lt;em&gt;any&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All of a sudden, this little &lt;em&gt;any&lt;/em&gt; is spreading like wildfire:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dangerous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="c1"&gt;// ✅ inferred to the number literal 5&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;okay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="c1"&gt;// 🚨 result is now `any`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dangerous&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;okay&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dangerous2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;

&lt;span class="c1"&gt;// 🚨 result2 is now `any` as well&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;dangerous2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Especially the object merging took me by surprise, but it makes sense. You can't build a union type with &lt;em&gt;any&lt;/em&gt;. Not even the awesome &lt;a href="https://tkdodo.eu/blog/the-power-of-const-assertions"&gt;const assertion&lt;/a&gt; will help you here. This is especially dangerous when using it together with React components, as spreading the result of a function that returns &lt;em&gt;any&lt;/em&gt; will make all props of that component fall back to &lt;em&gt;any&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myAnyUtil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ❗️ no other prop is type checked anymore&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"yes please"&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;myAnyUtil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      click me
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oops. Because we spread the result of &lt;em&gt;myAnyUtil&lt;/em&gt;, which returns &lt;em&gt;any&lt;/em&gt;, onto our &lt;em&gt;button&lt;/em&gt;, nothing is now type checked (if you are wondering: &lt;em&gt;onClick&lt;/em&gt; needs to accept a function, not a string). Remember, jsx is just syntatic sugar for &lt;em&gt;React.createElement&lt;/em&gt;, so the above code reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myAnyUtil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes please&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;myAnyUtil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can clearly see that the &lt;em&gt;props&lt;/em&gt; object we pass to our button is widened to &lt;em&gt;any&lt;/em&gt;, similar to the contrived example above, which is why the &lt;em&gt;onClick&lt;/em&gt; prop is also not type-checked.&lt;/p&gt;

&lt;p&gt;I believe this to be very dangerous, as its quite hidden. We rely on TypeScript to help us when refactoring, e.g. when altering union types. If I remove the &lt;em&gt;'secondary'&lt;/em&gt; variant of my Button component, and TypeScript wouldn't yell at me for all the existing usages, I would be lost in a larger code base.&lt;/p&gt;

&lt;p&gt;But with a leaking any on my component, TypeScript would just stay silent. It becomes as useful as a unit test where you forgot to assert anything. It's even worse than plain JavaScript, because you &lt;em&gt;think&lt;/em&gt; you're safe - but you're not.&lt;/p&gt;

&lt;h2&gt;
  
  
  When can this happen?
&lt;/h2&gt;

&lt;p&gt;I believe it happens more often than you might think, especially if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're &lt;a href="https://tkdodo.eu/blog/calling-java-script-from-type-script"&gt;calling JavaScript from TypeScript&lt;/a&gt; - such functions will very likely just return &lt;em&gt;any&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;You are using a 3rd party library that has weak types (&lt;a href="https://www.npmjs.com/package/lodash.get"&gt;lodash.get&lt;/a&gt; for example).&lt;/li&gt;
&lt;li&gt;You don't annotate your util functions with explicit return values and leak an &lt;em&gt;any&lt;/em&gt; from them.&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;With any, you can do anything, but everything is better than any.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— TkDodo&lt;/p&gt;

&lt;p&gt;The best advice I can give for situations where you have to use &lt;em&gt;any&lt;/em&gt; is to keep it confined to a very small scope to avoid it from leaking. You can also statically analyze your &lt;a href="https://github.com/plantain-00/type-coverage"&gt;type-coverage&lt;/a&gt; to get informed about places where &lt;em&gt;any&lt;/em&gt; is lurking around. If the coverage decreases on a PR, you might have a problem. Further, avoid 3rd party libraries that are written in JavaScript unless they have very good types. Lastly, ensuring that your own util functions don't leak anything can be achieved by explicitly enforcing return types on them, even though I also like to utilize type inference as much as possible. This is certainly a trade-off you'd need to be willing to make.&lt;/p&gt;




&lt;p&gt;That's it for today. Feel free to reach out to me on &lt;a href="https://twitter.com/tkdodo"&gt;twitter&lt;/a&gt;&lt;br&gt;
if you have any questions, or just leave a comment below ⬇️&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
