<?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: Darren Jennings</title>
    <description>The latest articles on Forem by Darren Jennings (@darrenjennings).</description>
    <link>https://forem.com/darrenjennings</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%2F213861%2F3cc58933-8f92-4cf4-8d3c-64e6036d42e6.png</url>
      <title>Forem: Darren Jennings</title>
      <link>https://forem.com/darrenjennings</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/darrenjennings"/>
    <language>en</language>
    <item>
      <title>Personal Gifs as a Service</title>
      <dc:creator>Darren Jennings</dc:creator>
      <pubDate>Wed, 08 Jul 2020 20:05:47 +0000</pubDate>
      <link>https://forem.com/darrenjennings/personal-gifs-as-a-service-1h7m</link>
      <guid>https://forem.com/darrenjennings/personal-gifs-as-a-service-1h7m</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fguuu.s3.amazonaws.com%2Fdgaas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fguuu.s3.amazonaws.com%2Fdgaas.png"&gt;&lt;/a&gt;&lt;br&gt;
I realized that generating random gifs, while wildly amusing, is not very&lt;br&gt;
personal. I also love using emojis 😅 but find them also to not be very&lt;br&gt;
personal. I wanted a way to communicate to my coworkers and friends, but also I&lt;br&gt;
wanted them to be able to see my ridiculously good-looking face 😝&lt;/p&gt;

&lt;p&gt;The result: &lt;a href="https://github.com/darrenjennings/darren-gifs" rel="noopener noreferrer"&gt;"darren gifs as a service"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I can call upon the internet (like zeus calling for lightening ⚡️) at any given moment to render a personalized, hand-crafted gif.&lt;/p&gt;

&lt;p&gt;Here's a view into what it looks like when invoking the alfred function in slack:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fguuu.s3.amazonaws.com%2Fdgaas_yw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fguuu.s3.amazonaws.com%2Fdgaas_yw.gif"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating your own gif service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Create Your Gifs
&lt;/li&gt;
&lt;li&gt; Upload it to a
publicly accessible location e.g.
&lt;a href="https://github.com/darrenjennings/darren-gifs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Add a Netlify redirect to a
Netlify site&lt;/li&gt;
&lt;li&gt; Invoke the url from anywhere&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Create Your Gifs
&lt;/h3&gt;

&lt;p&gt;Gifs can be created with a few services these days. The key is to optimize them so they're not too big. I use &lt;a href="http://www.appstore.com/GiphyCam" rel="noopener noreferrer"&gt;Giphy Cam&lt;/a&gt; which allows me to easily take gif selfies and add little effects to make them&lt;br&gt;
more fun like text or sparkles.&lt;/p&gt;

&lt;p&gt;I then tried to find a service that optimizes them. I found &lt;code&gt;gifsicle&lt;/code&gt; which optimizes gifs for space. My face is nice, but does it really need to be 10MB?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn &lt;span class="nb"&gt;install &lt;/span&gt;gifsicle
yarn gifsicle &lt;span class="nt"&gt;--batch&lt;/span&gt; &lt;span class="nt"&gt;--optimize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;200 &lt;span class="nt"&gt;--colors&lt;/span&gt; 256 &amp;lt;gif&amp;gt;.gif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload the Gifs to a Publicly Accessible Location
&lt;/h3&gt;

&lt;p&gt;I upload all my gifs to a GitHub repo. The optimization in the previous step is important here so that you don't store too much... You can easily store these in any CDN such as &lt;a href="https://cloudinary.com/" rel="noopener noreferrer"&gt;cloudinary&lt;/a&gt; or &lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;S3&lt;/a&gt;. The key here is that you want to be able to remember the name of your gifs so name them short and sweet like &lt;strong&gt;"yw.gif"&lt;/strong&gt; for "you're welcome" or &lt;strong&gt;"no.gif"&lt;/strong&gt;, &lt;strong&gt;"yes.gif"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep the &lt;span&gt;gif url&lt;/span&gt; of your publicly accessible gifs handy. You will need it in your next step.&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;a href="https://raw.githubusercontent.com/darrenjennings/darren-gifs/master/gifs/" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/darrenjennings/darren-gifs/master/gifs/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a Netlify Redirect to a Netlify Site
&lt;/h3&gt;

&lt;p&gt;Redirects in netlify are dead simple (and free). If you have an existing domain or Netlify site (did I mention they're free?) then you can add a redirect file in the root of the deployed site. Grab your &lt;span&gt;gif&lt;br&gt;
url&lt;/span&gt; and put it as the target of your redirect:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dist/_redirects&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://guuu.io/gifs/:name  https://raw.githubusercontent.com/darrenjennings/darren-gifs/master/gifs/:name.gif  301
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can access a gif on GitHub via a netlify redirect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://guuu.io/gifs/yay" rel="noopener noreferrer"&gt;https://guuu.io/gifs/yay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;becomes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/darrenjennings/darren-gifs/master/gifs/yay.gif" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/darrenjennings/darren-gifs/master/gifs/yay.gif&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;br&gt;
If your site has a build process, you will need to make sure that the _redirects file is in the same directory as your built site, e.g. /dist&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the file on my site for reference:&lt;br&gt;
&lt;a href="https://github.com/darrenjennings/guuu.io/blob/master/_redirects" rel="noopener noreferrer"&gt;guuu.io/_redirects&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Invoke the URL
&lt;/h3&gt;

&lt;p&gt;I am a big fan of &lt;a href="https://www.alfredapp.com/workflows/" rel="noopener noreferrer"&gt;Alfred&lt;/a&gt; after watching&lt;br&gt;
&lt;a href="https://twitter.com/johnlindquist" rel="noopener noreferrer"&gt;John Lindquist&lt;/a&gt; stream about Alfred workflows. I added a small workflow that allows me to type &lt;code&gt;d &amp;lt;gif_name&amp;gt;&lt;/code&gt; into my search bar which will paste the url wherever my computer cursor is. This allows me to react very quickly like the giphy slackbot but it works in any venue (Discord, Slack, Messages, Texting, etc.). Most everyone has access to the internet so it works well this way to host my own gifs and the previews even follow the redirects correctly. I also append a timestamp as a query param because sometimes slack won't unfurl a link that it's seen before, but I want to spam my coworkers with my gif even if they've seen it.&lt;/p&gt;

&lt;p&gt;I also find that my domain is short enough that I can easily type it out letter by letter, so even if I don't have an Alfred workflow I can usually call upon the links from memory. &lt;a href="https://guuu.io/gifs/beautiful" rel="noopener noreferrer"&gt;https://guuu.io/gifs/beautiful&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out my GitHub repo to see the source, and all my gifs and a copy of the alfred workflow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/darrenjennings/darren-gifs" rel="noopener noreferrer"&gt;https://github.com/darrenjennings/darren-gifs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/intent/tweet?text=Personal%20Gifs%20as%20a%20Service%20by%20%40darrenjennings%20https%3A//guuu.io/2020/darren-gifs/" rel="noopener noreferrer"&gt;Tweet this article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>netlify</category>
      <category>giphy</category>
      <category>alfred</category>
    </item>
    <item>
      <title>Data Fetching using Vue Hooks</title>
      <dc:creator>Darren Jennings</dc:creator>
      <pubDate>Tue, 11 Feb 2020 15:24:06 +0000</pubDate>
      <link>https://forem.com/darrenjennings/data-fetching-using-vue-hooks-bp</link>
      <guid>https://forem.com/darrenjennings/data-fetching-using-vue-hooks-bp</guid>
      <description>&lt;p&gt;Canonical URL: &lt;a href="https://guuu.io/2020/data-fetching-vue-composition-api/"&gt;https://guuu.io/2020/data-fetching-vue-composition-api/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I discuss data fetching in Vue - where it stands today, and how a library like &lt;a href="https://github.com/Kong/swrv"&gt;swrv&lt;/a&gt; can solve some common problems utilizing stale-while-revalidate caching.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Data fetching in an app can be a bit convoluted. If you're making XHR requests, you might see low latency from your high speed network connection or your low latency local network. You can emulate network conditions, but optimizing for speed can be an afterthought. While you want to empathize with your user base, implementing a frontend caching layer to speedup data fetches is usually low priority, especially if you reason that most of your users have high-speed connections / powerful devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching Data in Vue
&lt;/h2&gt;

&lt;p&gt;Traditionally in &lt;a href="http://vuejs.org/"&gt;Vue&lt;/a&gt;, you might fetch your data in the mounted hook, sometimes called "render then fetch"&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;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;:key=&lt;/span&gt;&lt;span class="s"&gt;"user.username"&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"user in users"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="si"&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;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="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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Users&lt;/span&gt;&lt;span class="dl"&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="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="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&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/users&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myJson&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myJson&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="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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are many options now in how a developer might go about&lt;br&gt;
&lt;a href="https://sergiodxa.com/articles/render-as-you-fetch/"&gt;fetching data&lt;/a&gt;, so even if you are triggering a fetch at different points in the render&lt;br&gt;
&lt;a href="https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram"&gt;lifecycle&lt;/a&gt;, your application typically will be constrained by the eventual &lt;strong&gt;inconsitent and cascading network latency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example if we also want to show all users with a link to their profile, e.g. a &lt;code&gt;&amp;lt;UserProfile&amp;gt;&lt;/code&gt; component, the profile page will then need to fetch data from &lt;strong&gt;both&lt;/strong&gt; the user and the user profile endpoints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uhvuOf-S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/swrv-loading.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uhvuOf-S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/swrv-loading.png" alt="vue data fetching for a user profile component"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;&amp;lt;UserProfile&amp;gt; component being loaded&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is common in RESTful endpoints when an endpoint doesn't support&lt;br&gt;
&lt;a href="https://typeorm.io/#/eager-and-lazy-relations"&gt;eager relations&lt;/a&gt;, specify join&lt;br&gt;
fields, or if you are not using &lt;a href="https://graphql.org/learn/queries/"&gt;GraphQL&lt;/a&gt;&lt;br&gt;
which is able to specify multiple return entities. The subsequent mounting and&lt;br&gt;
network cost blocking the render could get expensive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;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;v-if=&lt;/span&gt;&lt;span class="s"&gt;"profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt; &lt;span class="na"&gt;:src=&lt;/span&gt;&lt;span class="s"&gt;"profile.avatar"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Loading&lt;/span&gt; &lt;span class="nt"&gt;/&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;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="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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&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="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="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/profile`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;user&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="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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This gets a bit ugly and is not reactive in the event that &lt;code&gt;username&lt;/code&gt; changes. Let's clean it up a bit with the &lt;a href="https://vue-composition-api-rfc.netlify.com/"&gt;@vue/composition-api&lt;/a&gt; to &lt;a href="https://overreacted.io/writing-resilient-components/#principle-1-dont-stop-the-data-flow"&gt;keep the data flowing&lt;/a&gt; and utilize the new vue &lt;code&gt;setup&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;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;v-if=&lt;/span&gt;&lt;span class="s"&gt;"profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt; &lt;span class="na"&gt;:src=&lt;/span&gt;&lt;span class="s"&gt;"profile.avatar"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Loading&lt;/span&gt; &lt;span class="nt"&gt;/&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;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="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;watch&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/composition-api&lt;/span&gt;&lt;span class="dl"&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&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="nx"&gt;setup&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

    &lt;span class="c1"&gt;// when props.username changes, vue's reactivity automatically&lt;/span&gt;
    &lt;span class="c1"&gt;// registers the change and re-triggers the data fetch.&lt;/span&gt;
    &lt;span class="nx"&gt;watch&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/profile`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&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;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;profile&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="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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have the data &lt;em&gt;flowing&lt;/em&gt;, there is still a cost to rendering this component. If a user navigates away, then returns, the component will fetch the data all over again, even though the user just saw the data! This becomes frustrating for end users who are at the mercy of their network speeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching the Response
&lt;/h2&gt;

&lt;p&gt;Have you ever clicked a "back" link in a web application and the data that you &lt;em&gt;just saw&lt;/em&gt; is now taking an obscene amount of time to refetch? The browser can sometimes help with &lt;a href="https://tools.ietf.org/html/rfc7234#section-5"&gt;cache headers&lt;/a&gt;, and browser history cache, but in modern applications the server side rendered portion of our pages are only a segment of a user's navigation lifecycle. We need a multi-pronged caching strategy so that our dynamic pages, with client-side fetching, can be consistently fast and always online.&lt;sup&gt;[1]&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stale-while-revalidate
&lt;/h3&gt;

&lt;p&gt;Stale-while-revalidate (SWR) is a cache invalidation strategy popularized by HTTP &lt;a href="https://tools.ietf.org/html/rfc5861"&gt;RFC 5861&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a cached response is served stale due to the presence of this extension, the cache SHOULD attempt to revalidate it while still serving stale responses (i.e., without blocking).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key here is "not blocking". In our earlier example, the &lt;code&gt;&amp;lt;UserProfile&amp;gt;&lt;/code&gt; component would fetch from &lt;code&gt;/api/users&lt;/code&gt;, then &lt;code&gt;/api/users/:id/profile&lt;/code&gt;, always assuming that new fetches were fresh. This is a good thing, since users always want to see the latest data. However, this blocked the rendering of data until a  response was received, even if a user had seen the response recently.&lt;/p&gt;

&lt;p&gt;A SWR caching strategy would allow users to see stale data &lt;strong&gt;first&lt;/strong&gt; while fetching, giving an &lt;a href="https://en.wikipedia.org/wiki/Eventual_consistency"&gt;eventually consistent&lt;/a&gt; UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PYbPw-Z6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/stale-while-revalidate-data-fetching.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PYbPw-Z6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/stale-while-revalidate-data-fetching.png" alt="stale-while-revalidate data fetching vue"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;&lt;br&gt;
  Profile immediately returns from cache on the left, then once the fetch finishes,&lt;br&gt;
  then the new image/twitter handle is updated.&lt;br&gt;
&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the component, you might want to cache a response in a global store or localStorage. Here's our component might work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&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;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;watch&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/composition-api&lt;/span&gt;&lt;span class="dl"&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&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="nx"&gt;setup&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="nx"&gt;root&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;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getFromCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache/getCacheItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;key&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;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-profile`&lt;/span&gt;

    &lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// get STALE content and set data&lt;/span&gt;
      &lt;span class="nx"&gt;profile&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;getFromCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// WHILE-REVALIDATE and go fetch the data anyways,&lt;/span&gt;
      &lt;span class="c1"&gt;// producing immediately cached results, with an&lt;/span&gt;
      &lt;span class="c1"&gt;// eventually consistent UI.&lt;/span&gt;
      &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/profile`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&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;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;user&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache/setCacheItem&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;profile&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;profile&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This helps us get the strategy correct, but we'd like to have a library do this for us, so that we can have a simpler api while continuing to add new features: in-flight de-duplication, library agnostic fetching, error handling, loading states, different caching strategies, polling, onFocus revalidation etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing swrv
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.topronounced"&gt;swrv&lt;/a&gt; is a library using &lt;a href="https://github.com/vuejs/composition-api"&gt;@vue/composition-api&lt;/a&gt; hooks for remote data fetching. It is largely a port of &lt;a href="https://github.com/zeit/swr"&gt;swr&lt;/a&gt;. Our example can be refactored:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetcher&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;./fetcher&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;useSWRV&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;swrv&lt;/span&gt;&lt;span class="dl"&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserProfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&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="nx"&gt;setup&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSWRV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;fetcher&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSWRV&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="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="s2"&gt;/profile`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;fetcher&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;profile&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;In this example, the Vue Hook &lt;code&gt;useSWRV&lt;/code&gt; accepts a key and a fetcher function. &lt;code&gt;key&lt;/code&gt; is a unique identifier of the request, and here it is the URL of the API. The fetcher accepts the &lt;code&gt;key&lt;/code&gt; as its parameter and returns the data asynchronously. The &lt;code&gt;key&lt;/code&gt; can also be a function, with its own dependencies. The second &lt;code&gt;useSWRV&lt;/code&gt; hook actually has a dependency on the response from the first hook. &lt;a href="https://github.com/Kong/swrv"&gt;swrv&lt;/a&gt; will handle this by watching dependencies inside the key function and re-validate when these change. This is helpful for avoiding unnecessary fetches, and also reacting to key changes, in the event you'd like to pass in query params such as pagination/filtering.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useSWRV&lt;/code&gt; here returns 2 values: &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt;. When the request (fetcher) is not yet finished, data will be &lt;code&gt;undefined&lt;/code&gt;. And when we get a response, it sets &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; based on the result of fetcher and rerenders the component. This is because &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; are Vue&lt;br&gt;
&lt;a href="https://vue-composition-api-rfc.netlify.com/#detailed-design"&gt;Refs&lt;/a&gt;, and their values will be set by the fetcher response. The fetcher function can be any asynchronous function, so you can use your favorite data-fetching library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Kong/swrv"&gt;swrv&lt;/a&gt; handles some of the more complex feature sets, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in-flight promise &lt;strong&gt;de-duplication&lt;/strong&gt; in the event that a page loads the same data in multiple components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ElFKzMhk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/swrv-vue-data-fetching.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ElFKzMhk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://guuu.s3.amazonaws.com/swrv-vue-data-fetching.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Deduplication&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;focus and page availability revalidation events for when a user switches tabs or clicks away during the browser session. This helps with an app feeling consistently up to date, or &lt;strong&gt;"alive"&lt;/strong&gt;, all while being customizable to what the data source requires. e.g. expensive requests might want to limit as many fetches as possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;interval polling&lt;/strong&gt;, to check if data has been updated, all while still serving from cache, and stops polling if user is offline or the window is not active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;prefetching&lt;/strong&gt;, or "warming" the cache - useful for when you anticipate a user's actions like hovering over a link or preloading common page data.&lt;/li&gt;
&lt;li&gt;custom &lt;strong&gt;caching&lt;/strong&gt; strategies - by default cache is in-memory, but can be customized to use &lt;code&gt;localStorage&lt;/code&gt; for better offline experiences. &lt;code&gt;swrv&lt;/code&gt; manages the cache store, and provides ttl mechanisms for eviction.&lt;/li&gt;
&lt;li&gt;pagination. here is a short demo of using pagination in &lt;code&gt;swrv&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information on &lt;code&gt;swrv&lt;/code&gt; and it's features, check out the&lt;br&gt;
&lt;a href="https://github.com/Kong/swrv"&gt;Github Repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id="1" href="https://rauchg.com/2020/2019-in-review"&gt;1. Guillermo Rauch - 2019 in Review&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
    </item>
    <item>
      <title>How to Migrate to Vue 2.6</title>
      <dc:creator>Darren Jennings</dc:creator>
      <pubDate>Sat, 17 Aug 2019 17:23:48 +0000</pubDate>
      <link>https://forem.com/darrenjennings/how-to-migrate-to-vue-2-6-1443</link>
      <guid>https://forem.com/darrenjennings/how-to-migrate-to-vue-2-6-1443</guid>
      <description>&lt;p&gt;I recently migrated our static vue app at work from 2.x -&amp;gt; 2.6. Here are some notes that might help you:&lt;/p&gt;

&lt;h2&gt;
  
  
  Update your dependencies to 2.6
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add vue-template-compiler@^2.6.10 vue@^2.6.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Vuepress with Vue 2.6
&lt;/h2&gt;

&lt;p&gt;When Vuepress and Vue are in the same &lt;code&gt;package.json&lt;/code&gt;, there are some package version conflicts to note. If you have Vuepress ^1.0.2, you will see this kind of error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error:

Vue packages version mismatch:

- vue@2.6.10
- vue-server-renderer@2.5.22
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To resolve this, we can use a feature of &lt;code&gt;yarn&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yarn Resolutions
&lt;/h3&gt;

&lt;p&gt;Yarn comes with a feature called &lt;a href="https://yarnpkg.com/lang/en/docs/selective-version-resolutions/"&gt;Yarn Resolutions&lt;/a&gt;. This allows you to state explicit versions inside your &lt;code&gt;package.json&lt;/code&gt; when a package needs to resolve to a specific version.&lt;/p&gt;

&lt;p&gt;Remove &lt;code&gt;vue&lt;/code&gt;, &lt;code&gt;vue-template-compiler&lt;/code&gt;, and if you happen to have them in your dependencies or devDependencies (probably unlikely), remove &lt;code&gt;vue-server-renderer&lt;/code&gt; and &lt;code&gt;@vuepress/core&lt;/code&gt;. Then add a &lt;code&gt;resolutions&lt;/code&gt; field to your package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"resolutions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.6.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vue-template-compiler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.6.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vue-server-renderer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.6.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@vuepress/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.2"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Update Your Slot Template Syntax
&lt;/h2&gt;

&lt;p&gt;While the slot syntax got much simpler, it's fully backwards compatible. This is not a necessary change, but I recommend trying it out on your components using slots.&lt;/p&gt;

&lt;p&gt;Here is a renderless component that passes in some toggling functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ Old way --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;KToggle&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;slot-scope=&lt;/span&gt;&lt;span class="s"&gt;"{ isToggled, toggle }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;KButton&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;isToggled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggled&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;not toggled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/KButton&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;/KToggle&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ✅ &amp;gt;= 2.6 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;KToggle&lt;/span&gt; &lt;span class="na"&gt;v-slot=&lt;/span&gt;&lt;span class="s"&gt;"{ isToggled, toggle }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;KButton&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"toggle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ isToggled ? 'toggled' : 'not toggled' }}
  &lt;span class="nt"&gt;&amp;lt;/KButton&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/KToggle&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's an example with named slots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ Old way --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Header&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;slot=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;User 2&lt;span class="nt"&gt;&amp;lt;/h1&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;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"actions"&lt;/span&gt; &lt;span class="na"&gt;slot-scope=&lt;/span&gt;&lt;span class="s"&gt;"{canEdit}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"canEdit"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/users/2/edit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="nt"&gt;&amp;lt;/a&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;/Header&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ✅ &amp;gt;= 2.6 --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Header&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;#title&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- or v-slot:title--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;User 2&lt;span class="nt"&gt;&amp;lt;/h1&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;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;#actions=&lt;/span&gt;&lt;span class="s"&gt;"{canEdit}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- or v-slot:actions="&lt;/span&gt;{canEdit}"--&amp;gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"canEdit"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/users/2/edit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="nt"&gt;&amp;lt;/a&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;/Header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Check Components using Render Functions
&lt;/h2&gt;

&lt;p&gt;Return values of slots are now &lt;em&gt;always guaranteed to be a array or undefined&lt;/em&gt;. This &lt;a href="https://github.com/darrenjennings/vue-autosuggest/pull/112"&gt;bit me recently&lt;/a&gt; so one thing I'm doing now is testing multiple versions of Vue to catch bugs like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// in &amp;gt;2.6 this will always return an Array or undefined. Before, you could&lt;/span&gt;
    &lt;span class="c1"&gt;// get a single VNode or an Array of multiple VNodes and you would need to do&lt;/span&gt;
    &lt;span class="c1"&gt;// extra validations on the slots.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$scopedSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;There are some other changes in 2.6, but in this article I wanted to focus on what I found helpful to know, and write the article that I would have wanted to read when I was migrating to 2.6.&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evan You article on 2.6 release
&lt;a href="https://medium.com/the-vue-point/vue-2-6-released-66aa6c8e785e"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;docs on slots &lt;a href="https://vuejs.org/v2/guide/components-slots.html#ad"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gist.github.com/yyx990803/f5cba7711ab57b5d0dd1f8261ebee278"&gt;gist&lt;/a&gt;
explaining scoped slots return value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to the core team for helping me out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/sodatea"&gt;sodatea&lt;/a&gt; for the prior art in the
&lt;a href="https://github.com/vuejs/vue-cli/blob/cc66247950cf81552f4e50a934d60fa361bf7351/package.json#L77-L83"&gt;vue-cli&lt;/a&gt;
repo.&lt;/li&gt;
&lt;li&gt;Edd Yerburgh for
&lt;a href="https://github.com/vuejs/vue-test-utils/blob/dev/scripts/test-compat-all.sh"&gt;prior art&lt;/a&gt;
with testing multiple versions of vue.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
    </item>
  </channel>
</rss>
