<?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: BearStudio</title>
    <description>The latest articles on DEV Community by BearStudio (@bearstudio).</description>
    <link>https://dev.to/bearstudio</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%2Forganization%2Fprofile_image%2F6743%2F61a5f0f6-fb0e-44f6-b940-cbbcb47b09d7.png</url>
      <title>DEV Community: BearStudio</title>
      <link>https://dev.to/bearstudio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bearstudio"/>
    <language>en</language>
    <item>
      <title>Building a Full-Stack App Shouldn’t Feel Like Starting From Zero Every Time</title>
      <dc:creator>Ivan Dalmet</dc:creator>
      <pubDate>Tue, 02 Dec 2025 16:45:06 +0000</pubDate>
      <link>https://dev.to/bearstudio/building-a-full-stack-app-shouldnt-feel-like-starting-from-zero-every-time-2fgn</link>
      <guid>https://dev.to/bearstudio/building-a-full-stack-app-shouldnt-feel-like-starting-from-zero-every-time-2fgn</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.bearstudio.fr/" rel="noopener noreferrer"&gt;BearStudio&lt;/a&gt;, we start new web projects pretty often.&lt;br&gt;
And every time, the beginning felt the same: we spent hours assembling the foundation before we could build anything meaningful.&lt;/p&gt;

&lt;p&gt;Spin up a React and TypeScript project.&lt;br&gt;
Add routing.&lt;br&gt;
Choose a pattern for data fetching and mutations.&lt;br&gt;
Set up authentication.&lt;br&gt;
Install Prisma and wire migrations.&lt;br&gt;
Bring in Tailwind.&lt;br&gt;
Pick or build UI components.&lt;br&gt;
Add linting, tests, CI, Docker.&lt;/p&gt;

&lt;p&gt;By the time everything was in place, we still hadn’t shipped a real feature.&lt;br&gt;
None of this was particularly difficult.&lt;br&gt;&lt;br&gt;
It was just repetitive, and it drained energy before the interesting work began.&lt;/p&gt;

&lt;p&gt;That is what pushed us to create Start UI (web), an open-source full-stack starter.&lt;br&gt;
Repo: &lt;a href="https://github.com/BearStudio/start-ui-web" rel="noopener noreferrer"&gt;https://github.com/BearStudio/start-ui-web&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why TanStack Start?
&lt;/h2&gt;

&lt;p&gt;When we explored &lt;a href="//tanstack.com/start"&gt;TanStack Start&lt;/a&gt;, it matched the kind of developer experience we were looking for: explicit, modern, type-safe, and not overloaded with abstractions.&lt;/p&gt;

&lt;p&gt;It provides a clean foundation for routing, data loading and actions, while letting you stay close to the underlying React and server patterns. It gives structure without locking you in.&lt;/p&gt;

&lt;p&gt;TanStack Start does not try to solve everything, and we like that.&lt;br&gt;
It keeps the fundamentals simple and leaves room for architectural decisions. This is where our own stack comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where oRPC Fits In
&lt;/h2&gt;

&lt;p&gt;For client-server communication, we use &lt;a href="https://orpc.unnoq.com/" rel="noopener noreferrer"&gt;oRPC&lt;/a&gt;.&lt;br&gt;
It is not part of TanStack Start. It is a separate choice that gives us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fully typed procedure calls&lt;/li&gt;
&lt;li&gt;clearer separation of concerns&lt;/li&gt;
&lt;li&gt;no duplicated types&lt;/li&gt;
&lt;li&gt;predictable request and response flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;oRPC handles the application logic boundary, while TanStack Start takes care of routing and UI composition.&lt;br&gt;
The two work well together without stepping on each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup Pain We Wanted to Remove
&lt;/h2&gt;

&lt;p&gt;We did not create a starter because boilerplate is fun.&lt;br&gt;
We created it because every project kept hitting the same repetitive hurdles.&lt;/p&gt;

&lt;p&gt;Trying to rebuild a project structure we had already solved.&lt;br&gt;
Rewriting authentication flows that barely changed from one project to another.&lt;br&gt;
Configuring Prisma and handling migrations by hand.&lt;br&gt;
Keeping server and client types aligned without manual duplication.&lt;br&gt;
Rebuilding the same UI primitives again.&lt;br&gt;
Delaying tests until later and regretting it.&lt;br&gt;
Preparing Docker for the hundredth time.&lt;/p&gt;

&lt;p&gt;Each problem is small on its own.&lt;br&gt;
Together, they slow down the moment a project starts to feel real.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Start UI (web) Gives You From Day One
&lt;/h2&gt;

&lt;p&gt;The goal is simple. When you create a new project, you should be ready to build features almost immediately.&lt;/p&gt;

&lt;p&gt;You start with a clean React and TypeScript structure.&lt;br&gt;
Routing is set up with TanStack Start.&lt;br&gt;
oRPC gives you fully typed API procedures.&lt;br&gt;
Authentication is handled by Better Auth, already configured.&lt;br&gt;
Prisma is wired with schema and migrations.&lt;br&gt;
Tailwind is installed, and shadcn/ui gives you a solid set of components on day one.&lt;br&gt;
Unit and E2E tests run out of the box.&lt;br&gt;
ESLint, Prettier and CI are ready.&lt;br&gt;
Docker works for local and production environments.&lt;br&gt;
Storybook is included with a minimal design system.&lt;/p&gt;

&lt;p&gt;Nothing in this stack is here to constrain you.&lt;br&gt;
It is here to remove the repetitive parts so you can focus on what actually matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;The first days of a project should feel exciting.&lt;br&gt;
But when the setup phase drags on, that excitement fades quickly.&lt;/p&gt;

&lt;p&gt;Start UI (web) helps keep that momentum.&lt;br&gt;
It removes the tedious work so you can see real progress sooner and maintain it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who This Helps
&lt;/h2&gt;

&lt;p&gt;This starter works well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agencies and teams who frequently start new projects&lt;/li&gt;
&lt;li&gt;freelancers looking for a reliable baseline&lt;/li&gt;
&lt;li&gt;developers exploring TanStack Start in a real context&lt;/li&gt;
&lt;li&gt;anyone who wants to skip boilerplate and build faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not a framework.&lt;br&gt;
It is not rigid.&lt;br&gt;
It is a solid foundation you can build on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source and Continuously Improved
&lt;/h2&gt;

&lt;p&gt;We use Start UI (web) internally and refine it every time we hit a real-world need.&lt;br&gt;
You can explore it here:&lt;br&gt;
&lt;a href="https://github.com/BearStudio/start-ui-web" rel="noopener noreferrer"&gt;https://github.com/BearStudio/start-ui-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are trying to reach 2000 stars before Christmas.&lt;br&gt;
If it helps you or sparks ideas, a star would mean a lot.&lt;/p&gt;

&lt;p&gt;Thanks for reading. If you want to discuss TanStack Start, oRPC, Better Auth or anything else, we are always happy to chat.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Hi, do you know Rust?</title>
      <dc:creator>Yoann Fleury</dc:creator>
      <pubDate>Mon, 20 Oct 2025 06:56:23 +0000</pubDate>
      <link>https://dev.to/bearstudio/hi-do-you-know-rust-5gbn</link>
      <guid>https://dev.to/bearstudio/hi-do-you-know-rust-5gbn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This blog post is the translation of a &lt;a href="https://www.bearstudio.fr/blog/developpement/rust" rel="noopener noreferrer"&gt;french blog post I wrote for the BearStudio's blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article title sums up what my colleagues hear from me almost every day:&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;In this article, I’m sharing a list of resources for learning the &lt;a href="https://www.rust-lang.org" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; language (and I don’t mean the video game of the same name 😄).&lt;br&gt;
There’s no “Hello World” here, no lessons on conditionals or loops or borrowing or &lt;a href="https://www.bearstudio.fr/prestations/dev-back" rel="noopener noreferrer"&gt;backend development&lt;/a&gt;, just a curated collection of useful learning resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Rust?
&lt;/h2&gt;

&lt;p&gt;Rust is a programming language that continues to gain traction in the development world (it is, for instance, the &lt;a href="https://lkml.org/lkml/2021/12/6/461" rel="noopener noreferrer"&gt;second official language&lt;/a&gt; of the Linux kernel).&lt;br&gt;&lt;br&gt;
It contains concepts that are interesting to explore even if you don’t use it daily.&lt;/p&gt;

&lt;p&gt;Rust is highly present in the systems ecosystem, which is why we find many alternatives to classic command-line tools:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;&lt;code&gt;bat&lt;/code&gt;&lt;/a&gt; as an alternative to &lt;a href="https://en.wikipedia.org/wiki/Cat_(Unix)" rel="noopener noreferrer"&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sharkdp/fd" rel="noopener noreferrer"&gt;&lt;code&gt;fd&lt;/code&gt;&lt;/a&gt; as an alternative to &lt;a href="https://en.wikipedia.org/wiki/Find_(Unix)" rel="noopener noreferrer"&gt;&lt;code&gt;find&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rust is also used server-side — for example, the Bitwarden web services have a &lt;a href="https://github.com/dani-garcia/vaultwarden" rel="noopener noreferrer"&gt;Rust implementation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it doesn’t stop at backend programming. Rust also enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebAssembly development&lt;/li&gt;
&lt;li&gt;GUI development (for example: &lt;a href="https://github.com/emilk/egui" rel="noopener noreferrer"&gt;egui&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At BearStudio, more and more people are showing interest in the language, so I thought I’d compile the resources I discovered while learning it (learning which is still ongoing).&lt;/p&gt;

&lt;p&gt;Happy reading, and enjoy discovering Rust!&lt;/p&gt;




&lt;h2&gt;
  
  
  Discovering the power of a low-level language with the comfort of a high-level one
&lt;/h2&gt;

&lt;p&gt;To get started with Rust, the best resource is still &lt;strong&gt;&lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;The Rust Book&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Even though it’s theoretical, it helps you grasp Rust’s key concepts before really diving into code.&lt;/p&gt;

&lt;p&gt;The early chapters aren’t the most exciting — they cover concepts also found in other languages — but starting from &lt;strong&gt;chapter 4&lt;/strong&gt;, which introduces &lt;strong&gt;ownership&lt;/strong&gt;, things get much more interesting.&lt;/p&gt;

&lt;p&gt;To practice alongside your reading, I recommend cloning and working through:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/rust-lang/rustlings" rel="noopener noreferrer"&gt;https://github.com/rust-lang/rustlings&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It offers many small exercises that help you get familiar with reading and writing Rust while following The Rust Book.&lt;/p&gt;

&lt;p&gt;If you prefer an online introduction, here is a course from Microsoft:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://learn.microsoft.com/en-us/shows/beginners-series-to-rust/" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/shows/beginners-series-to-rust/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re ready to invest financially into a more advanced form of learning, you can check out &lt;strong&gt;&lt;a href="https://www.rustadventure.dev/" rel="noopener noreferrer"&gt;https://www.rustadventure.dev/&lt;/a&gt;&lt;/strong&gt; by &lt;strong&gt;Chris Biscardi&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can also progress with structured exercises via &lt;strong&gt;&lt;a href="https://exercism.org/" rel="noopener noreferrer"&gt;https://exercism.org/&lt;/a&gt;&lt;/strong&gt; and benefit from mentoring provided by the community.&lt;/p&gt;

&lt;p&gt;And if you like the community aspect, you can join the &lt;strong&gt;official Rust Discord&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;a href="https://discord.gg/rust-lang" rel="noopener noreferrer"&gt;https://discord.gg/rust-lang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to start learning Rust without installing anything locally? You can try &lt;strong&gt;Tour of Rust&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;a href="https://tourofrust.com/" rel="noopener noreferrer"&gt;https://tourofrust.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It lets you learn Rust directly in your browser using the official online playground.&lt;/p&gt;

&lt;p&gt;And to stay informed about everything happening around Rust, I recommend the newsletter &lt;strong&gt;This Week in Rust&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
&lt;a href="https://this-week-in-rust.org/" rel="noopener noreferrer"&gt;https://this-week-in-rust.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every week, it provides a curated list of links and resources to discover new projects, learn new concepts, or explore new dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  To go further
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.otso.fr/2021-12-05-marre-javascript-apprendre-rust" rel="noopener noreferrer"&gt;https://blog.otso.fr/2021-12-05-marre-javascript-apprendre-rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fettblog.eu/getting-started-with-rust/" rel="noopener noreferrer"&gt;https://fettblog.eu/getting-started-with-rust/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>learn</category>
      <category>translation</category>
    </item>
    <item>
      <title>Why did we create ui-state?</title>
      <dc:creator>Ivan Dalmet</dc:creator>
      <pubDate>Thu, 16 Oct 2025 14:05:20 +0000</pubDate>
      <link>https://dev.to/bearstudio/why-we-created-ui-state-308f</link>
      <guid>https://dev.to/bearstudio/why-we-created-ui-state-308f</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is a translation of the &lt;a href="https://www.bearstudio.fr/blog/developpement/pourquoi-on-a-cree-ui-state" rel="noopener noreferrer"&gt;original article on our website&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why did we create &lt;a href="https://github.com/BearStudio/ui-state" rel="noopener noreferrer"&gt;ui-state&lt;/a&gt;, a TypeScript library to manage ui state display? It all started after reading an excellent article by &lt;a href="https://x.com/TkDodo" rel="noopener noreferrer"&gt;Dominic Dorfmeister, aka TkDodo&lt;/a&gt; (we also recommend checking out &lt;a href="https://tkdodo.eu/blog/" rel="noopener noreferrer"&gt;his other posts on his blog&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In the article &lt;a href="https://tkdodo.eu/blog/component-composition-is-great-btw" rel="noopener noreferrer"&gt;Component Composition is great btw&lt;/a&gt;, TkDodo highlights a recurring problem: managing UI states (&lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;empty&lt;/code&gt;, &lt;code&gt;success&lt;/code&gt;, etc.) in a way that is &lt;strong&gt;readable, maintainable, and type-safe&lt;/strong&gt; without making your component structure explode.&lt;/p&gt;

&lt;p&gt;The typical starting point.&lt;br&gt;
You start by writing a simple component:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ShoppingList&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="nx"&gt;isPending&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="cm"&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;&lt;/span&gt;&lt;span class="nc"&gt;Card&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;CardHeading&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome 👋&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardHeading&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;CardContent&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;assignee&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;UserInfo&lt;/span&gt; &lt;span class="si"&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;assignee&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="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&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;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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="nc"&gt;ShoppingItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&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;item&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="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;CardContent&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;Card&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;At first glance, everything seems to "work."&lt;/p&gt;

&lt;p&gt;But things get messy quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can we have both &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;isPending&lt;/code&gt; at the same time?&lt;/li&gt;
&lt;li&gt;Does the absence of &lt;code&gt;data&lt;/code&gt; mean an error or an empty list?&lt;/li&gt;
&lt;li&gt;What happens if &lt;code&gt;data&lt;/code&gt; is present but empty?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You end up juggling several flags (isPending, data, isError, etc.) that can make two parts of the UI appear simultaneously, when that wasn't the intent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It becomes hard to read, test, and maintain.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TkDodo's proposed solution
&lt;/h2&gt;

&lt;p&gt;TkDodo suggests a clearer refactor based on &lt;code&gt;early returns&lt;/code&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Layout&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="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&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;&lt;/span&gt;&lt;span class="nc"&gt;Card&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;CardHeading&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome 👋 &lt;span class="si"&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;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="nc"&gt;CardHeading&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;CardContent&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&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;CardContent&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;Card&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ShoppingList&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="nx"&gt;isPending&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="cm"&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;isPending&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;&lt;/span&gt;&lt;span class="nc"&gt;Layout&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;Skeleton&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;Layout&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&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;EmptyScreen&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;Layout&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="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;Layout&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&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;title&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assignee&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;UserInfo&lt;/span&gt; &lt;span class="si"&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;assignee&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="kc"&gt;null&lt;/span&gt;&lt;span class="si"&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;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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="nc"&gt;ShoppingItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&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;item&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="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&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;This version is &lt;strong&gt;much clearer&lt;/strong&gt;, each state corresponds to a single render.&lt;/p&gt;

&lt;p&gt;But there's a tradeoff: &lt;strong&gt;You have to extract the layout into a separate component, and what if you don't want the entire screen to change?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Layout&lt;/code&gt; is duplicated in every branch. You also need to extract typing logic for the &lt;code&gt;Layout&lt;/code&gt; props. And if you want part of the interface (like a header or sidebar) to remain constant between states, or certain &lt;code&gt;Layout&lt;/code&gt; parts to depend on the state, your code structure starts to grow complex again.&lt;/p&gt;
&lt;h2&gt;
  
  
  What we wanted: a single, well-typed, active state, reusable anywhere
&lt;/h2&gt;

&lt;p&gt;At &lt;a href="https://www.bearstudio.fr" rel="noopener noreferrer"&gt;BearStudio&lt;/a&gt;, we wanted to keep the same core principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only one active state at a time&lt;/li&gt;
&lt;li&gt;Exhaustive type safety&lt;/li&gt;
&lt;li&gt;Readable display logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…but &lt;strong&gt;without breaking up the JSX&lt;/strong&gt; or restructuring the entire render around state cases.&lt;/p&gt;

&lt;p&gt;We wanted to be able to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Give us the current state, we'll handle it. Just make sure we cover every case."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  That's why we created ui-state
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;ui-state&lt;/code&gt;, you transform the response from a &lt;code&gt;useQuery&lt;/code&gt; (or any data source) into a single, explicit state, based on a single call to &lt;code&gt;getUiState&lt;/code&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUiState&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;@bearstudio/ui-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ShoppingList&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;query&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="cm"&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;ui&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUiState&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="k"&gt;if &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;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&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="o"&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;data&lt;/span&gt; &lt;span class="o"&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;empty&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&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;data&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;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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&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;CardHeading&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Welcome 👋 
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ui&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&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;empty&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="o"&gt;=&amp;gt;&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="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&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;data&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exhaustive&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;CardHeading&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;CardContent&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;ui&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;empty&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmptyScreen&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&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;data&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;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&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;assignee&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="nc"&gt;UserInfo&lt;/span&gt; &lt;span class="si"&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;assignee&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="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;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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="nc"&gt;ShoppingItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&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;item&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="si"&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;span class="nf"&gt;exhaustive&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;CardContent&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;Card&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;What we gain from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A single, well-defined state&lt;/strong&gt;, always up to date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type exhaustiveness&lt;/strong&gt; via &lt;code&gt;.exhaustive()&lt;/code&gt; ensures no case is forgotten.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic type narrowing&lt;/strong&gt; from TypeScript — for example, data is no longer optional since we've verified its existence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full rendering freedom&lt;/strong&gt;, without restructuring JSX around states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better testability&lt;/strong&gt;, you can test each UI state independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same concept as in TkDodo's article, but &lt;strong&gt;no need to split into multiple components or wrap your entire JSX around state handling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You keep &lt;strong&gt;clear logic and intact composition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔗 GitHub: &lt;a href="https://github.com/BearStudio/ui-state" rel="noopener noreferrer"&gt;https://github.com/BearStudio/ui-state&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>frontend</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
