<?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>Forem: Graeme George</title>
    <description>The latest articles on Forem by Graeme George (@graemegeorge).</description>
    <link>https://forem.com/graemegeorge</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%2F3465207%2F145c2324-95bf-437c-9b01-44c5014cf8c1.jpeg</url>
      <title>Forem: Graeme George</title>
      <link>https://forem.com/graemegeorge</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/graemegeorge"/>
    <language>en</language>
    <item>
      <title>Next Stop, Nuxt: A React Engineer’s Journey into Vue</title>
      <dc:creator>Graeme George</dc:creator>
      <pubDate>Thu, 28 Aug 2025 17:17:04 +0000</pubDate>
      <link>https://forem.com/graemegeorge/react-vue-a-senior-devs-self-study-bootcamp-2k38</link>
      <guid>https://forem.com/graemegeorge/react-vue-a-senior-devs-self-study-bootcamp-2k38</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome to a personal journey as I move from years of React and Next.js into the world of Vue 3 and Nuxt. It’s not meant to be a polished “final guide,” but rather a living, evolving document — part learning journal, part reference, and part cheat-sheet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The focus is on mapping familiar React and Next.js patterns to their Vue and Nuxt counterparts, with plenty of code snippets and “mini-labs” along the way. &lt;/p&gt;

&lt;p&gt;The tone here is intentionally hands-on and pragmatic. It’s written for experienced engineers who don’t need the basics explained, but want a direct path to becoming productive in Vue while still acknowledging that this is a journey, and the document will grow and change as we learn more.&lt;/p&gt;

&lt;p&gt;If you're a seasoned Vue engineer, please do feel free to leave a comment and tell me where I'm going wrong or share some great tips for others to consider and discuss. ✨&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Use This Document
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;👀 &lt;strong&gt;Jump in wherever you like.&lt;/strong&gt; Each section compares a React/Next.js pattern to its Vue/Nuxt equivalent. If you already know slots, skip ahead to provide/inject or routing.
&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Treat the code-labs as exercises.&lt;/strong&gt; They’re short, focused challenges designed to reinforce the concept. Copy, paste, break things, and make them your own.
&lt;/li&gt;
&lt;li&gt;🤷🏻 &lt;strong&gt;Don’t expect it to be finished.&lt;/strong&gt; This is a living document. I’ll update, refine, and expand as I encounter new patterns and idioms in Vue/Nuxt.
&lt;/li&gt;
&lt;li&gt;🧑🏻‍🎓 &lt;strong&gt;Use it as a bridge.&lt;/strong&gt; The goal is not to re-learn frontend from scratch, but to lean on your React knowledge while translating concepts into Vue’s mental model.
&lt;/li&gt;
&lt;li&gt;🐿️ &lt;strong&gt;Stay curious.&lt;/strong&gt; When in doubt, follow the links to the official React, Vue, and Nuxt docs — this doc is a companion, not a replacement.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  👷🏻 Setup (fast)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaffold Vue&lt;/strong&gt;: Vite + SFC + TS ready.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vue@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaffold Nuxt&lt;/strong&gt;: → &lt;code&gt;pnpm i &amp;amp;&amp;amp; pnpm dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nuxi@latest init my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data: &lt;a href="https://nuxt.com/docs/api/composables/use-async-data" rel="noopener noreferrer"&gt;&lt;code&gt;useAsyncData&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/api/composables/use-fetch" rel="noopener noreferrer"&gt;&lt;code&gt;useFetch&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/guide/directory-structure/pages" rel="noopener noreferrer"&gt;pages/ routing&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Mental model (reframe)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reactivity is granular&lt;/strong&gt;: &lt;br&gt;
derive with &lt;a href="https://vuejs.org/guide/essentials/computed" rel="noopener noreferrer"&gt;&lt;code&gt;computed&lt;/code&gt;&lt;/a&gt;, side-effects with &lt;a href="https://vuejs.org/guide/essentials/watchers" rel="noopener noreferrer"&gt;&lt;code&gt;watch&lt;/code&gt;/&lt;code&gt;watchEffect&lt;/code&gt;&lt;/a&gt; / (&lt;a href="https://vuejs.org/api/reactivity-core.html" rel="noopener noreferrer"&gt;API&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SFCs with &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;&lt;/strong&gt; are idiomatic; macros provide TS-friendly DX: &lt;br&gt;
&lt;a href="https://vuejs.org/api/sfc-script-setup" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://vuejs.org/api/sfc-spec" rel="noopener noreferrer"&gt;SFC spec&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Slots&lt;/strong&gt; are Vue's "children" (scoped slot props): &lt;br&gt;
&lt;a href="https://vuejs.org/guide/components/slots.html" rel="noopener noreferrer"&gt;Slots&lt;/a&gt; / &lt;a href="https://v3-migration.vuejs.org/breaking-changes/slots-unification" rel="noopener noreferrer"&gt;3.x unification&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context → provide/inject&lt;/strong&gt; (typed with &lt;code&gt;InjectionKey&lt;/code&gt;): &lt;br&gt;
&lt;a href="https://vuejs.org/guide/components/provide-inject" rel="noopener noreferrer"&gt;Provide/Inject&lt;/a&gt;, &lt;a href="https://vuejs.org/api/composition-api-dependency-injection" rel="noopener noreferrer"&gt;API + &lt;code&gt;InjectionKey&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portals/Keep state&lt;/strong&gt;: &lt;br&gt;
&lt;a href="https://vuejs.org/guide/built-ins/teleport" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Teleport&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://vuejs.org/guide/built-ins/keep-alive" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;KeepAlive&amp;gt;&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Component v-model&lt;/strong&gt; (two-way): &lt;br&gt;
&lt;a href="https://vuejs.org/guide/components/v-model" rel="noopener noreferrer"&gt;&lt;code&gt;v-model&lt;/code&gt; &amp;amp; &lt;code&gt;defineModel&lt;/code&gt; (3.4)&lt;/a&gt;, &lt;a href="https://blog.vuejs.org/posts/vue-3-4" rel="noopener noreferrer"&gt;Announcing 3.4&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Suspense&lt;/strong&gt; exists but is &lt;strong&gt;experimental&lt;/strong&gt;; in SSR prefer Nuxt's data composables: &lt;br&gt;
&lt;a href="https://vuejs.org/guide/built-ins/suspense" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/getting-started/data-fetching" rel="noopener noreferrer"&gt;Nuxt data fetching&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pattern translations + mini code-labs
&lt;/h2&gt;

&lt;p&gt;Each section: &lt;strong&gt;React&lt;/strong&gt; → &lt;strong&gt;Vue&lt;/strong&gt; (+ &lt;strong&gt;Nuxt twist&lt;/strong&gt;). Do the steps; verify visually.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Children/compound components → &lt;strong&gt;Slots &amp;amp; named slots&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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="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;Card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Header&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;.&lt;/span&gt;&lt;span class="nc"&gt;Body&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;.&lt;/span&gt;&lt;span class="nc"&gt;Footer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&gt; (SFC)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- components/Card.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&amp;lt;slot&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"footer"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;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 vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- usage --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Card&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;#header&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Content
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;#footer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Actions&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build &lt;code&gt;Card.vue&lt;/code&gt; with named slots.&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;slot props&lt;/strong&gt;: pass &lt;code&gt;sectionId&lt;/code&gt; from parent -&amp;gt; &lt;code&gt;#default="{ sectionId }"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Stretch: create &lt;code&gt;&amp;lt;Card.Header/&amp;gt;&lt;/code&gt; etc. as wrappers that render named slots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/components/slots.html" rel="noopener noreferrer"&gt;Slots&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤔 &lt;strong&gt;But wait!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm not sure about this pattern. React reads much closer to native html markup &lt;code&gt;&amp;lt;Card.Header /&amp;gt;&lt;/code&gt;, while it clearly belongs to the parent &lt;code&gt;&amp;lt;Card /&amp;gt;&lt;/code&gt; it remains it's own &lt;em&gt;unit&lt;/em&gt; of functionality. &lt;/p&gt;

&lt;p&gt;What if we went further to wrap the inner &lt;code&gt;template&lt;/code&gt; components in named slots like &lt;code&gt;&amp;lt;Card.Header /&amp;gt;&lt;/code&gt; etc so it can read in the same way in Vue. Maybe it wouldn't have any actual functional meaning but could replicate the great readability of React. &lt;/p&gt;

&lt;p&gt;But hang on, we need to think less "react" and more "vue" paradigms. Perhaps this isn't highlighting a drawback of Vue but rather the limitations of React?&lt;/p&gt;

&lt;p&gt;By writing code as &lt;code&gt;&amp;lt;template #header&amp;gt;&lt;/code&gt; we semantically mark it not only a native template but also as a &lt;code&gt;header&lt;/code&gt; slot, not just for a &lt;code&gt;Card&lt;/code&gt; but &lt;em&gt;anything&lt;/em&gt;! The code is therefore not only reusable but transferrable too 🤯&lt;/p&gt;

&lt;p&gt;Does this mean we have more control and say over &lt;em&gt;where&lt;/em&gt; we want to separate our concerns? Do we in fact get more semantic meaning this way...? &lt;/p&gt;




&lt;h3&gt;
  
  
  2) Context → &lt;strong&gt;provide/inject&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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;const&lt;/span&gt; &lt;span class="nx"&gt;Theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&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;dark&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&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;Theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&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;App&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;Theme&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Provider&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;strong&gt;Vue&lt;/strong&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="c1"&gt;// App.vue&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;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;provide&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;vue&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;ThemeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&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;InjectionKey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&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;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThemeKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Leaf.vue&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;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;inject&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;vue&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;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThemeKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide a reactive &lt;code&gt;ref('light')&lt;/code&gt; and a toggle function.&lt;/li&gt;
&lt;li&gt;Inject in deep child and verify updates.&lt;/li&gt;
&lt;li&gt;TS: use &lt;code&gt;InjectionKey&amp;lt;T&amp;gt;&lt;/code&gt; for type-safe provide/inject.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/components/provide-inject" rel="noopener noreferrer"&gt;Provide/Inject&lt;/a&gt;, &lt;a href="https://vuejs.org/api/composition-api-dependency-injection" rel="noopener noreferrer"&gt;API w/ &lt;code&gt;InjectionKey&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3) Hooks → &lt;strong&gt;Composables&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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;useMouse&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; &lt;span class="cm"&gt;/* setState/effect */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&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="c1"&gt;// composables/useMouse.ts&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;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onUnmounted&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;vue&lt;/span&gt;&lt;span class="dl"&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;useMouse&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;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&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="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&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;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&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;x&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nf"&gt;onUnmounted&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;move&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;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&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;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;composables/useMouse.ts&lt;/code&gt; and display &lt;code&gt;{ x }/{ y }&lt;/code&gt; in a component.&lt;/li&gt;
&lt;li&gt;Stretch: add throttling (requestAnimationFrame) and SSR-guard window access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: Community: &lt;a href="https://vueuse.org/" rel="noopener noreferrer"&gt;VueUse&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  4) &lt;code&gt;useMemo&lt;/code&gt; / &lt;code&gt;useCallback&lt;/code&gt; → &lt;strong&gt;computed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;computed&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;vue&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;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&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;items&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="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(...))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convert a derived selector to &lt;code&gt;computed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a heavy calc; confirm it recomputes only when deps change (log).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/essentials/computed" rel="noopener noreferrer"&gt;Computed&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  5) &lt;code&gt;useEffect&lt;/code&gt; side-effects → &lt;strong&gt;onMounted / watch / watchEffect&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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="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;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tick&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;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="nf"&gt;clearInterval&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="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onBeforeUnmount&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;onMounted&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;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tick&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;span class="nf"&gt;onBeforeUnmount&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;clearInterval&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace a &lt;code&gt;useEffect&lt;/code&gt; data sync with &lt;code&gt;watch(source, cb)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;watchEffect&lt;/code&gt; for auto-tracked dependencies; compare to &lt;code&gt;computed&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/essentials/watchers" rel="noopener noreferrer"&gt;Watchers&lt;/a&gt;, &lt;a href="https://vuejs.org/api/reactivity-core.html" rel="noopener noreferrer"&gt;Reactivity API&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  6) Controlled inputs → &lt;strong&gt;&lt;code&gt;v-model&lt;/code&gt; / &lt;code&gt;defineModel&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="si"&gt;}&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;strong&gt;Vue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Child two-way (3.4)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Child.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defineModel&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"model"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a reusable &lt;code&gt;&amp;lt;TextField v-model="name" /&amp;gt;&lt;/code&gt; with validation.&lt;/li&gt;
&lt;li&gt;Add multiple models: &lt;code&gt;defineModel('start')&lt;/code&gt;, &lt;code&gt;defineModel('end')&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Try &lt;code&gt;.trim&lt;/code&gt;/&lt;code&gt;.number&lt;/code&gt; modifiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/components/v-model" rel="noopener noreferrer"&gt;Component v-model + &lt;code&gt;defineModel&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://blog.vuejs.org/posts/vue-3-4" rel="noopener noreferrer"&gt;Vue 3.4&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  7) Portals → &lt;strong&gt;Teleport&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&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;return&lt;/span&gt; &lt;span class="nf"&gt;createPortal&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Teleport&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Modal&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Teleport&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render a modal/tooltip via &lt;code&gt;&amp;lt;Teleport to=\"#modals\"/&amp;gt;&lt;/code&gt; (dedicated node).&lt;/li&gt;
&lt;li&gt;SSR note: verify target exists client-side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/guide/built-ins/teleport" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Teleport&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  8) Error boundaries → &lt;strong&gt;&lt;code&gt;onErrorCaptured&lt;/code&gt; / Nuxt error pages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&gt;: &lt;code&gt;componentDidCatch&lt;/code&gt;/error boundaries.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Vue&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onErrorCaptured&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;onErrorCaptured&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&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="cm"&gt;/* log */&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nuxt&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global: &lt;a href="https://nuxt.com/docs/getting-started/error-handling" rel="noopener noreferrer"&gt;Error handling&lt;/a&gt;, &lt;code&gt;error.vue&lt;/code&gt; page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Throw in a child; handle with &lt;code&gt;onErrorCaptured&lt;/code&gt; and display fallback UI.&lt;/li&gt;
&lt;li&gt;Nuxt: create &lt;code&gt;error.vue&lt;/code&gt; and simulate an API failure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refs: &lt;a href="https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured" rel="noopener noreferrer"&gt;Vue error handling API&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/getting-started/error-handling" rel="noopener noreferrer"&gt;Nuxt errors&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  9) Suspense &amp;amp; async UI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: Suspense/RSC orchestrate async and streaming.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vue&lt;/strong&gt;: &lt;a href="https://vuejs.org/guide/built-ins/suspense" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;&lt;/a&gt; &lt;strong&gt;experimental&lt;/strong&gt;; prefer Nuxt data APIs for SSR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Nuxt data&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;pending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;useAsyncData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&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="nf"&gt;$fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PostList&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt; &lt;span class="na"&gt;:items=&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Skeleton&lt;/span&gt; &lt;span class="na"&gt;v-else-if=&lt;/span&gt;&lt;span class="s"&gt;"pending"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ErrorBox&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt; &lt;span class="na"&gt;:error=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement the above; confirm &lt;strong&gt;no double fetch&lt;/strong&gt; on hydrate.&lt;/li&gt;
&lt;li&gt;Compare &lt;code&gt;useFetch&lt;/code&gt; vs &lt;code&gt;useAsyncData&lt;/code&gt; for GET/POST. (Docs: &lt;a href="https://nuxt.com/docs/getting-started/data-fetching" rel="noopener noreferrer"&gt;Data fetching&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  10) Routing (React Router/Next) → &lt;strong&gt;Vue Router/Nuxt&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vue Router: nested routes, guards, programmatic nav.
Docs: &lt;a href="https://router.vuejs.org/guide/" rel="noopener noreferrer"&gt;Guide&lt;/a&gt;, &lt;a href="https://router.vuejs.org/guide/advanced/navigation-guards" rel="noopener noreferrer"&gt;Guards&lt;/a&gt;, &lt;a href="https://router.vuejs.org/guide/advanced/composition-api" rel="noopener noreferrer"&gt;Composition API&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Vue Router example&lt;/strong&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="c1"&gt;// router.ts&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;createRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createWebHistory&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;vue-router&lt;/span&gt;&lt;span class="dl"&gt;'&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createWebHistory&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Home.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Admin.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;auth&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="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// main.ts&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;createApp&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;&lt;strong&gt;Guard&lt;/strong&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAuthed&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;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;&lt;strong&gt;Nuxt&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File-based routes via &lt;code&gt;pages/&lt;/code&gt; (&lt;a href="https://nuxt.com/docs/guide/directory-structure/pages" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Access router/route via &lt;a href="https://nuxt.com/docs/4.x/api/composables/use-router" rel="noopener noreferrer"&gt;&lt;code&gt;useRouter&lt;/code&gt;&lt;/a&gt; / &lt;a href="https://nuxt.com/docs/api/composables/use-route" rel="noopener noreferrer"&gt;&lt;code&gt;useRoute&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code-lab&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Port an authenticated section with a global guard.&lt;/li&gt;
&lt;li&gt;Nuxt: create &lt;code&gt;pages/admin.vue&lt;/code&gt;; add navigation middleware; test redirects.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cheat Sheet
&lt;/h2&gt;

&lt;h2&gt;
  
  
  React → Vue Cheat-Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;React / Next.js&lt;/th&gt;
&lt;th&gt;Vue 3 / Nuxt 3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children" rel="noopener noreferrer"&gt;Children / compound components&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/components/slots.html" rel="noopener noreferrer"&gt;Slots &amp;amp; named slots&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/reference/react/createContext" rel="noopener noreferrer"&gt;Context (createContext / useContext)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/components/provide-inject.html" rel="noopener noreferrer"&gt;provide / inject&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/learn/reusing-logic-with-custom-hooks" rel="noopener noreferrer"&gt;Hooks (&lt;code&gt;useX&lt;/code&gt; functions)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/reusability/composables.html" rel="noopener noreferrer"&gt;Composables (&lt;code&gt;useX&lt;/code&gt;)&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://react.dev/reference/react/useMemo" rel="noopener noreferrer"&gt;useMemo / useCallback&lt;/a&gt; / &lt;a href="https://react.dev/reference/react/useCallback" rel="noopener noreferrer"&gt;useCallback&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/essentials/computed.html" rel="noopener noreferrer"&gt;computed&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/reference/react/useEffect" rel="noopener noreferrer"&gt;useEffect&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://vuejs.org/api/composition-api-lifecycle.html" rel="noopener noreferrer"&gt;onMounted / onUnmounted&lt;/a&gt;, &lt;a href="https://vuejs.org/guide/essentials/watchers.html" rel="noopener noreferrer"&gt;watch / watchEffect&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components" rel="noopener noreferrer"&gt;Controlled inputs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/components/v-model.html" rel="noopener noreferrer"&gt;v-model / defineModel (3.4+)&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/reference/react-dom/createPortal" rel="noopener noreferrer"&gt;Portals (createPortal)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://vuejs.org/guide/built-ins/teleport.html" rel="noopener noreferrer"&gt;Teleport&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary" rel="noopener noreferrer"&gt;Error Boundaries&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured" rel="noopener noreferrer"&gt;onErrorCaptured&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/getting-started/error-handling" rel="noopener noreferrer"&gt;Nuxt error handling&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://react.dev/reference/react/Suspense" rel="noopener noreferrer"&gt;Suspense &amp;amp; React Server Components&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://vuejs.org/guide/built-ins/suspense.html" rel="noopener noreferrer"&gt;&amp;lt;Suspense&amp;gt; (experimental)&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/getting-started/data-fetching" rel="noopener noreferrer"&gt;Nuxt useAsyncData/useFetch&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://nextjs.org/docs/app" rel="noopener noreferrer"&gt;Next.js App Router&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://nuxt.com/docs/guide/directory-structure/pages" rel="noopener noreferrer"&gt;Nuxt pages/ routing&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/guide/directory-structure/server" rel="noopener noreferrer"&gt;server/api (Nitro)&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Bonus: ecosystem mappings
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt;: Redux/Zustand → &lt;strong&gt;Pinia&lt;/strong&gt; (&lt;a href="https://pinia.vuejs.org/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, &lt;a href="https://vuex.vuejs.org/" rel="noopener noreferrer"&gt;Vuex note&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transitions&lt;/strong&gt;: &lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;TransitionGroup&amp;gt;&lt;/code&gt; built-in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserve component state&lt;/strong&gt;: &lt;code&gt;&amp;lt;KeepAlive&amp;gt;&lt;/code&gt; (&lt;a href="https://vuejs.org/guide/built-ins/keep-alive" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-only/islands&lt;/strong&gt;: Nuxt &lt;a href="https://nuxt.com/docs/api/components/client-only" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;ClientOnly&amp;gt;&lt;/code&gt;&lt;/a&gt; + &lt;a href="https://nuxt.com/docs/api/components/nuxt-island" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;NuxtIsland&amp;gt;&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Vue-native best practices (for React folks)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prefer &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; + macros (&lt;code&gt;defineProps/Emits/Model&lt;/code&gt;, &lt;code&gt;withDefaults&lt;/code&gt;) for clean TS.
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;computed&lt;/code&gt; for derivations&lt;/strong&gt;, &lt;code&gt;watch&lt;/code&gt;/&lt;strong&gt;&lt;code&gt;watchEffect&lt;/code&gt;&lt;/strong&gt; for side-effects.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't destructure props/reactive objects&lt;/strong&gt; unless via &lt;code&gt;toRefs/toRef&lt;/code&gt; (keep reactivity).
&lt;/li&gt;
&lt;li&gt;Reach for &lt;strong&gt;composables&lt;/strong&gt; for shared logic; study patterns in VueUse.
&lt;/li&gt;
&lt;li&gt;Be SSR-aware (no direct &lt;code&gt;window&lt;/code&gt;/&lt;code&gt;document&lt;/code&gt; on server); if needed, gate with &lt;code&gt;process.client&lt;/code&gt; in Nuxt.
&lt;/li&gt;
&lt;li&gt;For modals/menus, prefer Teleport to dedicated container elements.
&lt;/li&gt;
&lt;li&gt;Performance: start with defaults-fine-grained tracking does heavy lifting. Only micro-opt once measured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Primary docs: &lt;a href="https://vuejs.org/guide/essentials/computed" rel="noopener noreferrer"&gt;Computed&lt;/a&gt;, &lt;a href="https://vuejs.org/guide/essentials/watchers" rel="noopener noreferrer"&gt;Watchers&lt;/a&gt;, &lt;a href="https://vuejs.org/api/sfc-script-setup" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://vuejs.org/guide/components/provide-inject" rel="noopener noreferrer"&gt;Provide/Inject&lt;/a&gt;, &lt;a href="https://vuejs.org/guide/built-ins/teleport" rel="noopener noreferrer"&gt;Teleport&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Nuxt for Next engineers (quick map)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt;: &lt;code&gt;useAsyncData&lt;/code&gt; / &lt;code&gt;useFetch&lt;/code&gt; (SSR-first; payload de-dupes client refetch).
Docs: &lt;a href="https://nuxt.com/docs/api/composables/use-async-data" rel="noopener noreferrer"&gt;useAsyncData&lt;/a&gt;, &lt;a href="https://nuxt.com/docs/api/composables/use-fetch" rel="noopener noreferrer"&gt;useFetch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server routes&lt;/strong&gt;: &lt;code&gt;server/api/*.ts&lt;/code&gt; (Nitro).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing&lt;/strong&gt;: &lt;code&gt;pages/&lt;/code&gt; filesystem; nested layouts &amp;amp; middleware.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Islands&lt;/strong&gt;: &lt;a href="https://nuxt.com/docs/api/components/nuxt-island" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;NuxtIsland&amp;gt;&lt;/code&gt;&lt;/a&gt;; &lt;strong&gt;client-only&lt;/strong&gt;: &lt;a href="https://nuxt.com/docs/api/components/client-only" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;ClientOnly&amp;gt;&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors&lt;/strong&gt;: &lt;a href="https://nuxt.com/docs/getting-started/error-handling" rel="noopener noreferrer"&gt;Error handling&lt;/a&gt;, &lt;code&gt;error.vue&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4-week self-study plan
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;W1&lt;/strong&gt;: Rebuild a small React app in Vue SFCs; slots + composables + Pinia.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W2&lt;/strong&gt;: Router 4 (guards, nested layouts); transitions; Teleport + accessibility.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W3&lt;/strong&gt;: Migrate to Nuxt: file routing, data fetching, API routes, error pages.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W4&lt;/strong&gt;: Production polish-payload caching, &lt;code&gt;&amp;lt;KeepAlive&amp;gt;&lt;/code&gt;, perf checks, CI build.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Appendix: official docs index
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vue core: &lt;a href="https://vuejs.org/guide/essentials/computed" rel="noopener noreferrer"&gt;Computed&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/essentials/watchers" rel="noopener noreferrer"&gt;Watchers&lt;/a&gt; · &lt;a href="https://vuejs.org/api/sfc-script-setup" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/scaling-up/sfc.html" rel="noopener noreferrer"&gt;SFC&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/components/provide-inject" rel="noopener noreferrer"&gt;Provide/Inject&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/built-ins/teleport" rel="noopener noreferrer"&gt;Teleport&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/built-ins/keep-alive" rel="noopener noreferrer"&gt;KeepAlive&lt;/a&gt; · &lt;a href="https://vuejs.org/guide/built-ins/suspense" rel="noopener noreferrer"&gt;Suspense (exp.)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Router: &lt;a href="https://router.vuejs.org/guide/" rel="noopener noreferrer"&gt;Guide&lt;/a&gt; · &lt;a href="https://router.vuejs.org/guide/advanced/navigation-guards" rel="noopener noreferrer"&gt;Guards&lt;/a&gt; · &lt;a href="https://router.vuejs.org/guide/advanced/composition-api" rel="noopener noreferrer"&gt;Composition API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pinia: &lt;a href="https://pinia.vuejs.org/" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nuxt: &lt;a href="https://nuxt.com/docs/getting-started/data-fetching" rel="noopener noreferrer"&gt;Data fetching&lt;/a&gt; · &lt;a href="https://nuxt.com/docs/guide/directory-structure/pages" rel="noopener noreferrer"&gt;pages/&lt;/a&gt; · &lt;a href="https://nuxt.com/docs/getting-started/error-handling" rel="noopener noreferrer"&gt;Errors&lt;/a&gt; · &lt;a href="https://nuxt.com/docs/api/components/client-only" rel="noopener noreferrer"&gt;ClientOnly&lt;/a&gt; · &lt;a href="https://nuxt.com/docs/api/components/nuxt-island" rel="noopener noreferrer"&gt;NuxtIsland&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>learning</category>
      <category>frontend</category>
      <category>vue</category>
      <category>react</category>
    </item>
    <item>
      <title>Rethinking Responsibility: Empowering Engineers</title>
      <dc:creator>Graeme George</dc:creator>
      <pubDate>Thu, 28 Aug 2025 15:43:32 +0000</pubDate>
      <link>https://forem.com/graemegeorge/rethinking-responsibility-empowering-engineers-d9h</link>
      <guid>https://forem.com/graemegeorge/rethinking-responsibility-empowering-engineers-d9h</guid>
      <description>&lt;p&gt;Talking about the responsibility of programmers is tricky. It’s easy to slip into judgment or create a defensive atmosphere. Yet when handled thoughtfully, it can unlock empowerment-not guilt. Here’s how.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Challenges Engineers Face
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feeling judged too often&lt;/strong&gt;&lt;br&gt;
In &lt;a href="https://psychsafety.com/blametropism/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blame-heavy environments&lt;/a&gt;, engineers hide mistakes and avoid innovation-because speaking up can feel risky. Blame culture dampens psychological safety and hampers creativity (&lt;a href="https://www.tandfonline.com/doi/full/10.1080/08956308.2023.2164439?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;study here&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Culture doesn’t reward performance&lt;/strong&gt;&lt;br&gt;
Productivity obsessed organisations (tickets closed, hours logged, features shipped) rarely acknowledge creativity, mentorship, or architectural thinking leaving engineers uninspired.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The freedom to hide&lt;/strong&gt;&lt;br&gt;
When recognition is scarce, disappearing into routine feels safer than standing out, especially for those cautious about judgment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The 10/90 imbalance&lt;/strong&gt;&lt;br&gt;
A minority trying to carry the workload can lead to burnout and disengagement, leaving the majority untapped.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Reframing Responsibility
&lt;/h2&gt;

&lt;p&gt;Responsibility isn't about fault, it's about ownership, growth, and contribution without fear.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eradicate blame culture&lt;/strong&gt; Replace "who failed?" with "what failed, and how can we fix it?" This reflects the idea of a &lt;a href="https://en.wikipedia.org/wiki/Just_culture?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Just Culture&lt;/a&gt;, a shift from finger-pointing to systemic learning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spot and cultivate strengths&lt;/strong&gt;&lt;br&gt;
People thrive when their unique skills are valued, not just measured by output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Celebrate visibility, not heroics&lt;/strong&gt;&lt;br&gt;
Reward incremental collaboration, knowledge-sharing and mentoring, not just flashy releases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encourage creativity and safe risk-taking&lt;/strong&gt;&lt;br&gt;
When mistakes become learning opportunities, innovation emerges.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Building a Culture That Empowers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shift from output to outcomes&lt;/strong&gt;&lt;br&gt;
Elegance and stability should be recognised as much as new features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reward curiosity&lt;/strong&gt;&lt;br&gt;
Allocate time for exploration, hack days, brown-bag sessions, so curiosity becomes part of the culture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Promote psychological safety&lt;/strong&gt;&lt;br&gt;
Google's &lt;a href="https://rework.withgoogle.com/intl/en/guides/understanding-team-effectiveness?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Project Aristotle&lt;/a&gt; found psychological safety to be the top predictor of team effectiveness. Teams where members feel safe admitting mistakes, asking questions, and offering ideas consistently outperform others (&lt;a href="https://www.leaderfactor.com/learn/project-aristotle-psychological-safety?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;LeaderFactor summary&lt;/a&gt;, &lt;a href="https://psychsafety.com/googles-project-aristotle/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Psychsafety overview&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Offer autonomy and clarity&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Autonomy boosts psychological safety which in turn improves performance and reflexivity (&lt;a href="https://arxiv.org/abs/2109.15034?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;research here&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recognise the unseen work&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Celebrating documentation, mentorship, and small fixes is crucial for morale.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Leadership: Enablers, Not Judges
&lt;/h2&gt;

&lt;p&gt;Managers and tech leads must recognise that responsibility lies in cultivating an environment where developers can take pride and ownership over their work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leaders must inspire and be a reminder as to &lt;em&gt;why their work matters&lt;/em&gt;.
&lt;/li&gt;
&lt;li&gt;They should be visible in celebrating wins - not just failures. This prevents the all &lt;strong&gt;&lt;em&gt;too&lt;/em&gt;&lt;/strong&gt; common feeling that &lt;em&gt;"they're there for your failures, never your successes."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing Reflection
&lt;/h2&gt;

&lt;p&gt;Engineering culture is too often shaped by fear of judgment, irrelevance, or mistakes. But responsibility, when reframed, becomes empowering. It frees developers to take risks, grow, and collaborate. Leadership plays a vital role too-not by policing, but by enabling and celebrating.&lt;/p&gt;

&lt;p&gt;This isn't the final word, it's a starting point. Let's experiment, wonder, and build environments where engineers feel safe to bring their pride and potential-and leaders shoulder responsibility for making that possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://psychsafety.com/blametropism/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Blametropism and Blame Culture in Teams&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://rework.withgoogle.com/intl/en/guides/understanding-team-effectiveness?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Google’s Project Aristotle – What Makes Teams Effective&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Just_culture?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Just Culture: Moving Beyond Blame&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2109.15034?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Psychological Safety and Agile Teams (arXiv Research)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>workplace</category>
      <category>culture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Composability in Component Architecture: Lessons from React, Radix UI, and Beyond</title>
      <dc:creator>Graeme George</dc:creator>
      <pubDate>Thu, 28 Aug 2025 13:56:36 +0000</pubDate>
      <link>https://forem.com/graemegeorge/composability-in-component-architecture-lessons-from-react-radix-ui-and-beyond-4g8b</link>
      <guid>https://forem.com/graemegeorge/composability-in-component-architecture-lessons-from-react-radix-ui-and-beyond-4g8b</guid>
      <description>&lt;p&gt;Component-driven development has matured dramatically in the last decade. As frameworks evolve, so too do the paradigms and principles that shape how we build UI systems. One concept that has stood the test of time—arguably even strengthened—is &lt;strong&gt;composability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.radix-ui.com/primitives/docs/guides/composition" rel="noopener noreferrer"&gt;Radix UI&lt;/a&gt; for example, embodies this philosophy beautifully:&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;Accordion&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="s2"&gt;radix-ui&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="k"&gt;default &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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Item&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Header&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Trigger&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Header&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Item&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;Accordion&lt;/span&gt;&lt;span class="p"&gt;.&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common pattern I like to use are primitive parts to make up a card.&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="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;CardHeader&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;CardBody&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;CardFooter&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than bloating a single &lt;code&gt;&amp;lt;Card /&amp;gt;&lt;/code&gt; component with endless props (&lt;code&gt;showHeader&lt;/code&gt;, &lt;code&gt;footerVariant&lt;/code&gt;, &lt;code&gt;isCompact&lt;/code&gt;), Radix opts for composability. Each subcomponent does one thing well, and you stitch them together to achieve flexibility. &lt;/p&gt;

&lt;p&gt;This reflects principles drawn from functional programming and single responsibility, while also challenging outdated dogma like DRY (Don't Repeat Yourself).&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "God Components" Fail
&lt;/h2&gt;

&lt;p&gt;Many React developers fall into the trap of the "God Component":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes a huge object of props.&lt;/li&gt;
&lt;li&gt;Bloated with &lt;code&gt;if/else&lt;/code&gt; conditionals.&lt;/li&gt;
&lt;li&gt;Hard to test, hard to extend, brittle to refactors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider this anti-pattern:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;
  &lt;span class="na"&gt;showHeader&lt;/span&gt;
  &lt;span class="na"&gt;footerVariant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"compact"&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt;
  &lt;span class="na"&gt;showBorder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;isLoading&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Content goes here
&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single component is burdened with far too much knowledge. Even worse, when props are passed as new object references (&lt;code&gt;{}&lt;/code&gt;), React often sees them as “different” on each render, causing unnecessary re-renders. Objects-as-props are another subtle performance trap.&lt;/p&gt;

&lt;p&gt;By contrast, composability avoids these pitfalls:&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="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;CardHeader&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardHeader&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;CardBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Some content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardBody&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;CardFooter&lt;/span&gt; &lt;span class="na"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Footer text&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardFooter&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Each part is responsible for itself.&lt;/li&gt;
&lt;li&gt;Props stay shallow and predictable.&lt;/li&gt;
&lt;li&gt;Testing is trivial: test &lt;code&gt;&amp;lt;CardHeader /&amp;gt;&lt;/code&gt; in isolation.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Composability Over DRY
&lt;/h2&gt;

&lt;p&gt;"Don’t Repeat Yourself" (DRY) once dominated software engineering. In UI, however, &lt;strong&gt;repetition can be healthy&lt;/strong&gt;. Consistency of patterns matters more than absolute deduplication.&lt;/p&gt;

&lt;p&gt;For example, repeating the structure of composable layouts—like headers, bodies, and footers—creates familiarity. This makes it easier for other developers to navigate your codebase and for design systems to scale. Over-abstraction in the name of DRY often introduces more indirection and fragility than it removes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Inspirations from Functional Programming
&lt;/h2&gt;

&lt;p&gt;Composability mirrors functional programming’s ethos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small, pure functions&lt;/strong&gt; → small, pure components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline composition&lt;/strong&gt; → JSX composition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No side effects&lt;/strong&gt; → predictable rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mindset makes components easy to test, reason about, and reuse. Just as FP warns against large impure functions, frontend engineers should resist "God Components."&lt;/p&gt;




&lt;h2&gt;
  
  
  Composability in VueJS
&lt;/h2&gt;

&lt;p&gt;React isn’t the only framework where this philosophy thrives. Vue has long encouraged composability via &lt;strong&gt;slots&lt;/strong&gt; and, more recently, the &lt;strong&gt;Composition API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A Vue &lt;code&gt;&amp;lt;Card&amp;gt;&lt;/code&gt; might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Card&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;#header&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CardHeader&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/CardHeader&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;CardBody&amp;gt;&lt;/span&gt;Some content&lt;span class="nt"&gt;&amp;lt;/CardBody&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;#footer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CardFooter&lt;/span&gt; &lt;span class="na"&gt;compact&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Footer text&lt;span class="nt"&gt;&amp;lt;/CardFooter&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key parallels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue’s &lt;strong&gt;slots&lt;/strong&gt; are React’s &lt;strong&gt;children&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Vue’s &lt;strong&gt;Composition API&lt;/strong&gt; encourages extracting small, reusable logic units, just like React hooks.&lt;/li&gt;
&lt;li&gt;Both frameworks are moving away from monolithic components toward &lt;strong&gt;patterns over props&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lessons from React translate directly into Vue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid God Components.&lt;/li&gt;
&lt;li&gt;Embrace composable slots/components.&lt;/li&gt;
&lt;li&gt;Repetition of patterns is good—don’t fear repeating yourself.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Is Composability Still Relevant in React Server Components (RSC)?
&lt;/h2&gt;

&lt;p&gt;With Next.js and RSC, some devs worry composability may be less relevant. After all, server components bring new paradigms: data fetching in the component, zero client-side JavaScript by default.&lt;/p&gt;

&lt;p&gt;But composability &lt;strong&gt;remains core&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server components benefit even more from composability&lt;/strong&gt;: smaller components fetch their own data, keep concerns isolated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming UI&lt;/strong&gt; aligns with composability: headers can load before footers, independent of one another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client components&lt;/strong&gt; wrap naturally into the same patterns. A &lt;code&gt;CardHeader&lt;/code&gt; can be a client component for interactivity, while &lt;code&gt;CardBody&lt;/code&gt; stays a server component for static content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, the move to RSC makes "God Components" even riskier. Bloated components become harder to cache, harder to stream, and harder to split between client/server boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Composability isn’t just a coding style—it’s a survival strategy for scalable UI systems. From React’s Radix UI to Vue’s slots, the philosophy of &lt;strong&gt;small, focused, repeatable patterns&lt;/strong&gt; is stronger than ever.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;God Components are brittle; composability is robust.&lt;/li&gt;
&lt;li&gt;DRY is overrated; repetition of patterns fosters clarity.&lt;/li&gt;
&lt;li&gt;Functional programming principles map perfectly onto modern component design.&lt;/li&gt;
&lt;li&gt;Composability transcends libraries/frameworks: React/NextJS and Vue /Nuxt converge here.&lt;/li&gt;
&lt;li&gt;Even in the age of React Server Components, composability is more critical, not less.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The takeaway: keep building &lt;strong&gt;small, composable, repeatable components.&lt;/strong&gt; Your future self—and your teammates—will thank you.&lt;/p&gt;

</description>
      <category>react</category>
      <category>vue</category>
      <category>nextjs</category>
      <category>radix</category>
    </item>
  </channel>
</rss>
